[
  {
    "path": ".github/workflows/nebula-ci.yml",
    "content": "name: \"CI\"\non:\n  push:\n    branches:\n      - '*'\n    tags-ignore:\n      - '*'\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        # test against JDK 8\n        java: [ 8  ]\n    name: CI with Java ${{ matrix.java }}\n    steps:\n      - uses: actions/checkout@v6\n      - name: Setup jdk\n        uses: actions/setup-java@v5\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - uses: actions/cache@v5\n        id: gradle-cache\n        with:\n          path: ~/.gradle/caches\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }}\n          restore-keys: |\n            - ${{ runner.os }}-gradle-\n      - uses: actions/cache@v5\n        id: gradle-wrapper-cache\n        with:\n          path: ~/.gradle/wrapper\n          key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }}\n          restore-keys: |\n            - ${{ runner.os }}-gradlewrapper-\n      - name: Build with Gradle\n        run: ./gradlew --info --stacktrace build\n        env:\n          CI_NAME: github_actions\n          CI_BUILD_NUMBER: ${{ github.sha }}\n          CI_BUILD_URL: 'https://github.com/${{ github.repository }}'\n          CI_BRANCH: ${{ github.ref }}\n          COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/nebula-publish.yml",
    "content": "name: \"Publish candidate/release to NetflixOSS and Maven Central\"\non:\n  push:\n    tags:\n      - v*.*.*\n      - v*.*.*-rc.*\n  release:\n    types:\n      - published\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    environment: Publish\n    steps:\n      - uses: actions/checkout@v6\n      - name: Setup jdk 8\n        uses: actions/setup-java@v5\n        with:\n          java-version: 1.8\n          distribution: 'zulu'\n      - uses: actions/cache@v5\n        id: gradle-cache\n        with:\n          path: ~/.gradle/caches\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }}\n          restore-keys: |\n            - ${{ runner.os }}-gradle-\n      - uses: actions/cache@v5\n        id: gradle-wrapper-cache\n        with:\n          path: ~/.gradle/wrapper\n          key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }}\n          restore-keys: |\n            - ${{ runner.os }}-gradlewrapper-\n      - name: Publish candidate\n        if: contains(github.ref, '-rc.')\n        run: ./gradlew --info --stacktrace -Prelease.useLastTag=true candidate\n        env:\n          NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }}\n          NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }}\n          NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }}\n          NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }}\n      - name: Publish release\n        if: (!contains(github.ref, '-rc.'))\n        run: ./gradlew --info -Prelease.useLastTag=true final\n        env:\n          NETFLIX_OSS_SONATYPE_USERNAME: ${{ secrets.ORG_SONATYPE_USERNAME }}\n          NETFLIX_OSS_SONATYPE_PASSWORD: ${{ secrets.ORG_SONATYPE_PASSWORD }}\n          NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }}\n          NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }}\n          NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }}\n          NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }}\n"
  },
  {
    "path": ".github/workflows/nebula-snapshot.yml",
    "content": "name: \"Publish snapshot to NetflixOSS and Maven Central\"\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    environment: Publish\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - name: Set up JDK\n        uses: actions/setup-java@v5\n        with:\n          java-version: 8\n          distribution: 'zulu'\n      - uses: actions/cache@v5\n        id: gradle-cache\n        with:\n          path: |\n            ~/.gradle/caches\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}\n      - uses: actions/cache@v5\n        id: gradle-wrapper-cache\n        with:\n          path: |\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }}\n      - name: Build\n        run: ./gradlew build snapshot\n        env:\n          NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }}\n          NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }}\n          NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }}\n          NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled source #\n###################\n*.com\n*.class\n*.dll\n*.exe\n*.o\n*.so\n\n# Packages #\n############\n# it's better to unpack these files and commit the raw source\n# git has its own built in compression methods\n*.7z\n*.dmg\n*.gz\n*.iso\n*.jar\n*.rar\n*.tar\n*.zip\n\n# Logs and databases #\n######################\n*.log\n\n# OS generated files #\n######################\n.DS_Store*\nehthumbs.db\nIcon?\nThumbs.db\n\n# Editor Files #\n################\n*~\n*.swp\n\n# Gradle Files #\n################\n.gradle\n.m2\n\n# Build output directies\ntarget/\nbuild/\n\n# IntelliJ specific files/directories\nout\n.idea\n*.ipr\n*.iws\n*.iml\natlassian-ide-plugin.xml\n\n# Eclipse specific files/directories\n.classpath\n.project\n.settings\n.metadata\nbin/\n\n# NetBeans specific files/directories\n.nbattrs\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Hystrix Releases #\n\n### Version 1.5.13 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.13%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.13/)) ###\n\n- [Pull 1621](https://github.com/Netflix/Hystrix/pull/1621) Fixed bug where an unsubscription of a command in half-open state leaves circuit permanently open\n- [Pull 1605](https://github.com/Netflix/Hystrix/pull/1605) Change return value on unsubscribe to Observable.empty().  Thanks @atoulme !\n- [Pull 1615](https://github.com/Netflix/Hystrix/pull/1615) Updated Gradle to version 4.0. Thanks @wlsc !\n- [Pull 1616](https://github.com/Netflix/Hystrix/pull/1616) Javanica: Wrong hystrix event type for fallback missing.  Thanks @dmgcodevil  !\n- [Pull 1606](https://github.com/Netflix/Hystrix/pull/1606) Escape user entered input to avoid HTML injection. This fixes #1456.  Thanks @atoulme  !\n- [Pull 1595](https://github.com/Netflix/Hystrix/pull/1595) Possibility to add custom root node for command and thread pool metrics.  Thanks @dstoklosa !\n- [Pull 1587](https://github.com/Netflix/Hystrix/pull/1587) Throw IllegalStateException if request cache is not available when clearing.  Thanks @jack-kerouac !\n\n### Version 1.5.12 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.12%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.12/)) ###\n\n- [Pull 1586](https://github.com/Netflix/Hystrix/pull/1586) Start streams for CodaHale metric consumer, ot get it actually working\n- [Pull 1584](https://github.com/Netflix/Hystrix/pull/1584) Javanica: Wire up allowMaximumSizeToDivergeFromCoreSize thread-pool property\n- [Pull 1585](https://github.com/Netflix/Hystrix/pull/1585) Fix actualMaximumSize Codahale threadpool metric calculation\n- [Pull 1567](https://github.com/Netflix/Hystrix/pull/1567) Fix interaction between ExceptionNotWrappedInHystrix and HystrixBadRequestException.  Thanks @gagoman !\n- [Pull 1576](https://github.com/Netflix/Hystrix/pull/1576) Fix permyriad calculation for 99.9p latency\n- [Pull 1524](https://github.com/Netflix/Hystrix/pull/1524) Javanica: Support rx.Single or rx.Completable types.  Thanks @dmgcodevil !\n- [Pull 1574](https://github.com/Netflix/Hystrix/pull/1574) Add unit-test for using a Completable in a HystrixObservableCommand\n- [Pull 1572](https://github.com/Netflix/Hystrix/pull/1572) Javanica: Wire up maximumSize thread-pool property.  Thanks @dmgcodevil !\n- [Pull 1573](https://github.com/Netflix/Hystrix/pull/1573) Javanica: Don't get cause from HystrixBadRequestException if null.  Thanks @dmgcodevil !\n- [Pull 1570](https://github.com/Netflix/Hystrix/pull/1570) Only create HystrixContextRunnable in timeout case lazily, when timeout is fired\n- [Pull 1568](https://github.com/Netflix/Hystrix/pull/1568) Made circuit-opening happen in background thread, powered by metric streams\n- [Pull 1561](https://github.com/Netflix/Hystrix/pull/1561) Add error-handling for unexpected errors to servlet writes in metric sample servlet\n- [Pull 1556](https://github.com/Netflix/Hystrix/pull/1556) Typo fix in Javanica fallback log. Thanks @Thunderforge !\n- [Pull 1551](https://github.com/Netflix/Hystrix/pull/1551) Match colors in multiple circuit-breaker status case.  Thanks @eunmin !\n- [Pull 1547](https://github.com/Netflix/Hystrix/pull/1547) Support multiple circuit-breaker statuses in dashboard against aggregated data.  Thanks @eunmin !\n- [Pull 1539](https://github.com/Netflix/Hystrix/pull/1539) Fix unintentionally shared variable in hystrix-metrics-event-stream-jaxrs.  Thanks @justinjose28 !\n- [Pull 1535](https://github.com/Netflix/Hystrix/pull/1535) Move markCommandExecution after markEvent SUCCESS to allow eventNotifier to have full context of execution.  Thanks @bltb!\n\n### Version 1.5.11 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.11%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.11/)) ###\n\n- [Pull 1531](https://github.com/Netflix/Hystrix/pull/1531) Add assertion to dashboard receiving metrics data.  Thanks @lholmquist !\n- [Pull 1529](https://github.com/Netflix/Hystrix/pull/1529) Remove commons-collection as dependency of hystrix-javanica.  Thanks @Psynbiotik !\n- [Pull 1532](https://github.com/Netflix/Hystrix/pull/1532) Move metrics subscription out of synchronized block in HealthCountsStream to limit time spent holding a lock.\n- [Pull 1513](https://github.com/Netflix/Hystrix/pull/1513) Fixed COMMAND_MAX_ACTIVE metrics for Coda Hale metrics.  Thanks @chrisgray !\n- [Pull 1515](https://github.com/Netflix/Hystrix/pull/1515) Fixed comment typo in HystrixCommand.  Thanks @kmkr !\n- [Pull 1512](https://github.com/Netflix/Hystrix/pull/1512) Upgrade codahale metrics-core to 3.2.2.  Thanks @chrisgray !\n- [Pull 1507](https://github.com/Netflix/Hystrix/pull/1507) README typo fix. Thanks @PiperChester !\n- [Pull 1503](https://github.com/Netflix/Hystrix/pull/1503) Allow BadRequest exceptions to not be attached if user explicitly wants unwrapped exceptions.  Thanks @mNantern !\n- [Pull 1502](https://github.com/Netflix/Hystrix/pull/1502) Remove useless code in HystrixConcurrencyStrategy.  Thanks @zzzvvvxxxd !\n- [Pull 1495](https://github.com/Netflix/Hystrix/pull/1495) Add hystrix-metrics-event-stream-jaxrs.  Thanks @justinjose28 !\n- [Pull 1498](https://github.com/Netflix/Hystrix/pull/1498) Upgrade Servo to 0.10.1 in hystrix-servo-metrics-publisher\n\n### Version 1.5.10 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.10%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.10/)) ###\n\n- [Pull 1489](https://github.com/Netflix/Hystrix/pull/1489) Added rollingMaxConcurrentExecutionCount to CodaHale metrics publisher.  Thanks @LuboVarga !\n- [Pull 1481](https://github.com/Netflix/Hystrix/pull/1481) Add sanity checking to HystrixCommandAspect to debug unreproducible cases.  Thanks @dmgcodevil !\n- [Pull 1482](https://github.com/Netflix/Hystrix/pull/1482) Make it possible to re-use fallback methods in Javanica.  (Addresses #1446).  Thanks @dmgcodevil !\n- [Pull 1488](https://github.com/Netflix/Hystrix/pull/1488) Fix spelling mistakes in Javanica docs.  Thanks @bltb!\n- [Pull 1475](https://github.com/Netflix/Hystrix/pull/1475) Added example usage of CodaHale metrics publisher.  Thanks @LuboVarga !\n- [Pull 1469](https://github.com/Netflix/Hystrix/pull/1469) Fix possible concurrency bug.  Thanks @petercla! \n- [Pull 1453](https://github.com/Netflix/Hystrix/pull/1453) Add Javanica unit test for NotWrapped checked exception.  Thanks @tbvh!\n\n### Version 1.5.9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.9%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.9/)) ###\n\n* [Pull 1423](https://github.com/Netflix/Hystrix/pull/1423) Write correct value to error log when maximumSize < coreSize.  Thanks @diver-in-sky!\n* [Pull 1412](https://github.com/Netflix/Hystrix/pull/1412) Javanica: raiseHystrixExceptions support for Observables.  Thanks @michaelcowan !\n* [Pull 1441](https://github.com/Netflix/Hystrix/pull/1441) Use Gretty Gradle plugin for hystrix-examples-webapp \n* [Pull 1442](https://github.com/Netflix/Hystrix/pull/1442) Fix handling of client-connect/disconnect never getting released if it occurs before metrics start getting produced by hystrix-metrics-event-stream.  Thanks for review, @mattnelson!\n* [Pull 1444](https://github.com/Netflix/Hystrix/pull/1444) More efficient server thread release in hystrix-metrics-event-stream.  Thanks @mattnelson for the suggestion!\n* [Pull 1443](https://github.com/Netflix/Hystrix/pull/1443) Use Gretty Gradle plugin for hystrix-dashboard\n* [Pull 1445](https://github.com/Netflix/Hystrix/pull/1445) Add missing onUnsubscribe hook to execution hooks\n* [Pull 1414](https://github.com/Netflix/Hystrix/pull/1414) Introduce NotWrappedByHystrix exception type to indicate Hystrix should propagate it back without wrapping in a HystrixRuntimeException.  Thanks @tbvh!\n* [Pull 1448](https://github.com/Netflix/Hystrix/pull/1448) Remove dependency on jackson-cbor in hystrix-serialization.  This belongs in a different module.  Existing public methods now throw an exception.\n* [Pull 1435](https://github.com/Netflix/Hystrix/pull/1435) Allow the property `allowMaximumSixeToDivergeFromCoreSize` to be set dynamically.  Thanks @ptab!\n* [Pull 1447](https://github.com/Netflix/Hystrix/pull/1447) Allow the property `allowMaximumSixeToDivergeFromCoreSize` to be set dynamically. \n* [Pull 1449](https://github.com/Netflix/Hystrix/pull/1435) Introduce a distinction between `maximumSize` (configured value) and `actualMaximumSize` (value used to set the thread pool maximum size).  Publish both values to make understanding configuration more straightforward.  Thanks @ptab!\n\n### Version 1.5.8 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.8%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.8/)) ###\n\n* [Pull 1419](https://github.com/Netflix/Hystrix/pull/1419) When user has not opted in to letting core/maximum threadpools diverge, ensure dynamic updates to coreSize apply to both\n* [Pull 1415](https://github.com/Netflix/Hystrix/pull/1415) Fix spelling mistake in comments.  Thanks @starlight36 !\n\n### Version 1.5.7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.7%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.7/)) ###\n\n* [Pull 1408](https://github.com/Netflix/Hystrix/pull/1408) Fix Clojure key name for collapsing.  Thanks @crimeminister !\n* [Pull 1407](https://github.com/Netflix/Hystrix/pull/1407) Reset percentile snapshot whenever all HystrixRollingPercentile buckets are empty\n* [Pull 1397](https://github.com/Netflix/Hystrix/pull/1397) Javanica: Add option to raise HystrixRuntimeException\n* [Pull 1399](https://github.com/Netflix/Hystrix/pull/1399) Add configuration to make users opt-in to allowing coreSize and maximumSize to diverge.  See config [here] (https://github.com/Netflix/Hystrix/wiki/Configuration#allowMaximumSizeToDivergeFromCoreSize)\n* [Pull 1396](https://github.com/Netflix/Hystrix/pull/1396) If command is unsubscribed before any work is done, return Observable.empty().  \n* [Pull 1393](https://github.com/Netflix/Hystrix/pull/1393) Javanica: Performance improvement by caching weavingMode boolean.  Thanks @ricardoletgo !\n* [Pull 1389](https://github.com/Netflix/Hystrix/pull/1389) Javanica: Send fallback exception to client instead of primary command.  Thanks @dmgcodevil !\n* [Pull 1385](https://github.com/Netflix/Hystrix/pull/1385) Bump jmh Gradle plugin to 0.3.1.  Thanks @monkey-mas!\n* [Pull 1382](https://github.com/Netflix/Hystrix/pull/1382) Bump jmh to 1.15.  Thanks @monkey-mas!\n* [Pull 1380](https://github.com/Netflix/Hystrix/pull/1380) Add jmh test for open-circuit case\n* [Pull 1376](https://github.com/Netflix/Hystrix/pull/1376) Clean up documentation around thread keep-alive.  Thanks @bitb !\n* [Pull 1375](https://github.com/Netflix/Hystrix/pull/1375) Remove cancelled tasks from threadpool queue\n* [Pull 1371](https://github.com/Netflix/Hystrix/pull/1371) Allow core and maximum size of threadpools to diverge.\n\n### Version 1.5.6 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.6%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.6/)) ###\n\n* [Pull 1368](https://github.com/Netflix/Hystrix/pull/1368) Upgrade jmh to 1.14.1\n* [Pull 1365](https://github.com/Netflix/Hystrix/pull/1365) Upgrade to Gradle 3.1 / Nebula 3.4.0\n* [Pull 1364](https://github.com/Netflix/Hystrix/pull/1364) Fix backwards-incompatibility introduced in #1356\n* [Pull 1363](https://github.com/Netflix/Hystrix/pull/1363) Fix metrics regression where thread pool objects without any executions were being sent out in metrics streams\n* [Pull 1360](https://github.com/Netflix/Hystrix/pull/1360) Convert command-construction jmh test to single-shot\n* [Pull 1356](https://github.com/Netflix/Hystrix/pull/1356) Add better AppEngine detection mechanism that allows GAE-Flexible to work like any other JVM.  Thanks @cadef!\n* [Pull 1353](https://github.com/Netflix/Hystrix/pull/1353) Upgrade to RxJava 1.2.0\n* [Pull 1351](https://github.com/Netflix/Hystrix/pull/1351) Remove histogram object-pooling\n* [Pull 1336](https://github.com/Netflix/Hystrix/pull/1336) Overall Dashboard UX improvements.  Thanks @kennedyoliveira !\n* [Pull 1320](https://github.com/Netflix/Hystrix/pull/1320) Adding example of HystrixObservableCollapser.  Thanks @zsoltm !\n* [Pull 1341](https://github.com/Netflix/Hystrix/pull/1341) Javanica fix for handling commands with generic types.  Thanks @dmgcodevil ! \n* [Pull 1340](https://github.com/Netflix/Hystrix/pull/1340) Refactor how commands determine if fallbacks are user-defined\n\n### Version 1.5.5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.5%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.5/)) ###\n\n* [Pull 1323](https://github.com/Netflix/Hystrix/pull/1323) Remove ReactiveSocket modules and change Jenkins release process back to JDK7\n\n### Version 1.5.4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.4%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.4/)) ###\n\n* [Pull 1308](https://github.com/Netflix/Hystrix/pull/1308) Update jmh to 1.13\n* [Pull 1310](https://github.com/Netflix/Hystrix/pull/1310) Update nebula.netflixoss Gradle plugin to 3.3.0\n* [Pull 1309](https://github.com/Netflix/Hystrix/pull/1309) Update HdrHistogram to 2.1.9\n* [Pull 1307](https://github.com/Netflix/Hystrix/pull/1307) Update RxJava to 1.1.8\n* [Pull 1306](https://github.com/Netflix/Hystrix/pull/1306) Update Clojure to 1.7.0 and nebula-clojure-plugin to 4.0.1\n* [Pull 1305](https://github.com/Netflix/Hystrix/pull/1305) Update Gradle to 2.14\n* [Pull 1304](https://github.com/Netflix/Hystrix/pull/1304) Make all metrics streams multicast.\n* [Pull 1303](https://github.com/Netflix/Hystrix/pull/1303) Update RxNetty to 0.4.17\n* [Pull 1302](https://github.com/Netflix/Hystrix/pull/1302) Manual merge of #1265.  Interrupt execution thread on HystrixCommand#queue()#cancel(true).  Thanks @mmanciop!\n* [Pull 1300](https://github.com/Netflix/Hystrix/pull/1300) Update all completion state for scalar command in the onNext handling\n* [Pull 1294](https://github.com/Netflix/Hystrix/pull/1294) Make sure that threadpools shutdown when asked to.  Thanks @thesmith!\n* [Pull 1297](https://github.com/Netflix/Hystrix/pull/1297) Fix typo in README.  Thanks @ManishMaheshwari!\n* [Pull 1295](https://github.com/Netflix/Hystrix/pull/1295) Fix typo in README.  Thanks @C-Otto!\n* [Pull 1273](https://github.com/Netflix/Hystrix/pull/1273) Corrected ignoreExceptions for Observable-returning methods.  Thanks @jbojar!\n* [Pull 1197](https://github.com/Netflix/Hystrix/pull/1197) Eureka integration for Hystrix dashboard.  Thanks @diegopacheco!\n* [Pull 1278](https://github.com/Netflix/Hystrix/pull/1278) Prevent duplicate arguments from getting into a single collapser RequestBatch\n* [Pull 1277](https://github.com/Netflix/Hystrix/pull/1277) Make HystrixCollapser.toObservable lazy\n* [Pull 1276](https://github.com/Netflix/Hystrix/pull/1276) Make HystrixObservableCollapser.toObservable lazy\n* [Pull 1271](https://github.com/Netflix/Hystrix/pull/1271) Fix race condition in all of the Hystrix*Key.asKey methods.  Thanks @daniilguit!\n* [Pull 1274](https://github.com/Netflix/Hystrix/pull/1274) Make AbstractCommand.toObservable lazy\n* [Pull 1270](https://github.com/Netflix/Hystrix/pull/1270) Fix deprecation warnings by upgrading RxJava and Netty usages\n* [Pull 1269](https://github.com/Netflix/Hystrix/pull/1269) Rework hystrix-data-stream module to just include serialization logic\n* [Pull 1259](https://github.com/Netflix/Hystrix/pull/1259) Javanica: added DefaultProperties annotation.  Thanks @dmgcodevil!\n* [Pull 1261](https://github.com/Netflix/Hystrix/pull/1261) Add toString() to key implementations.  Thanks @mebigfatguy!\n* [Pull 1258](https://github.com/Netflix/Hystrix/pull/1258) Javanica: Change getMethod to recursively search in parent types.  Thanks @dmgcodevil!\n* [Pull 1255](https://github.com/Netflix/Hystrix/pull/1255) Introduce intermediate data streams module [LATER REVERTED - SEE #1269 ABOVE]\n* [Pull 1254](https://github.com/Netflix/Hystrix/pull/1254) Allow multiple consumers of sample data to only trigger work once and share data\n* [Pull 1251](https://github.com/Netflix/Hystrix/pull/1251) Fix Dashboard RPS\n* [Pull 1247](https://github.com/Netflix/Hystrix/pull/1247) Call thread pool size setters only when pool size changes.  Thanks @yanglifan!\n* [Pull 1246](https://github.com/Netflix/Hystrix/pull/1246) Move HystrixDashboardStream to hystrix-core\n* [Pull 1244](https://github.com/Netflix/Hystrix/pull/1244) Fix handling of invalid weavingMode property.  Thanks @mebigfatguy!\n* [Pull 1238](https://github.com/Netflix/Hystrix/pull/1238) Local variable caching fixups.  Thanks @mebigfatguy!\n* [Pull 1236](https://github.com/Netflix/Hystrix/pull/1236) ReactiveSocket metrics client/server\n* [Pull 1235](https://github.com/Netflix/Hystrix/pull/1235) Add demo that composes async command executions\n* [Pull 1231](https://github.com/Netflix/Hystrix/pull/1231) Make inner classes static where possible, and remove outer class reference.  Thanks @mebigfatguy!\n* [Pull 1229](https://github.com/Netflix/Hystrix/pull/1229) Remove dead Setter class from RequestCollapserFactory. Thanks @mebigfatguy!\n* [Pull 1225](https://github.com/Netflix/Hystrix/pull/1225) Remove unused thunk from HystrixCommandMetrics.  Thanks @mebigfatguy!\n* [Pull 1224](https://github.com/Netflix/Hystrix/pull/1224) Remove dead field from RequestCollapserFactory.  Thanks @mebigfatguy!\n* [Pull 1221](https://github.com/Netflix/Hystrix/pull/1221) Improve grammar in comments and log messages.  Thanks @dysmento !\n* [Pull 1211](https://github.com/Netflix/Hystrix/pull/1211) Add ReactiveSocket metrics stream.  Thanks @robertroeser!\n* [Pull 1219](https://github.com/Netflix/Hystrix/pull/1219) Move map lookup outside of loop in collapser code.  Thanks @mebigfatguy!\n\n### Version 1.5.3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.3%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.3/)) ###\n\nThe largest new feature in this release is that cancellation is now supported.  Either calling `cancel()` on the result of `HystrixCommand.queue()` or `unsubscribe()` on the result of `HystrixCommand.toObservable().subscribe()` will propagate the cancellation to the underlying work.\n\n* [Pull 1218](https://github.com/Netflix/Hystrix/pull/1218) Fixing unsubscription races by modeling explicit FSMs for command and thread execution state\n* [Pull 1217](https://github.com/Netflix/Hystrix/pull/1217) Remove dead code in RequestEventsStream.  Thanks @mebigfatguy!\n* [Pull 1214](https://github.com/Netflix/Hystrix/pull/1214) Fix Servo metric calculation.  Bug identified by @AchimWe.\n* [Pull 1213](https://github.com/Netflix/Hystrix/pull/1213) Use parameterized logging.  Thanks @mebigfatguy!\n* [Pull 1212](https://github.com/Netflix/Hystrix/pull/1212) Correct logging contexts.  Thanks @mebigfatguy!\n* [Pull 1210](https://github.com/Netflix/Hystrix/pull/1210) Javanica: code optimization to fetch parameters only if needed.  Thanks @mebigfatguy!\n* [Pull 1209](https://github.com/Netflix/Hystrix/pull/1209) Fixed thread-state cleanup to happen on unsubscribe or terminate\n* [Pull 1208](https://github.com/Netflix/Hystrix/pull/1208) Reorganization of HystrixCollapser/HystrixObservableCollapser logic to support cancellation\n* [Pull 1207](https://github.com/Netflix/Hystrix/pull/1207) Fix command concurrency metric in light of cancellation\n* [Pull 1206](https://github.com/Netflix/Hystrix/pull/1206) Added subscribeOn to HystrixObservableCommand in JMH test to make it async\n* [Pull 1204](https://github.com/Netflix/Hystrix/pull/1204) Reorganization of AbstractCommand logic to support cancellation\n* [Pull 1198](https://github.com/Netflix/Hystrix/pull/1198) Release semaphores upon cancellation.\n* [Pull 1194](https://github.com/Netflix/Hystrix/pull/1194) Improved tests readability a bit by letting exceptions propagate out.  Thanks @caarlos0!\n* [Pull 1193](https://github.com/Netflix/Hystrix/pull/1193) More tests using HystrixRequestContext rule.  Thanks @caarlos0!\n* [Pull 1181](https://github.com/Netflix/Hystrix/pull/1181) Deprecate getter and setter for unused collapsingEnabled property in Collapser Setter.  Thanks @nluchs!\n* [Pull 1184](https://github.com/Netflix/Hystrix/pull/1184) migrating all hystrix-javanica tests to hystrix-junit.  Thanks @caarlos0!\n* [Pull 1147](https://github.com/Netflix/Hystrix/pull/1147) Added hystrix-junit.  Thanks @caarlos0!\n\n### Version 1.4.26 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.26%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.26/)) ###\n\n* [Pull 1169](https://github.com/Netflix/Hystrix/pull/1169) Javanica: Switch hystrix-javanica to use getExecutionException, which returns Exception object even when command is not executed\n\n### Version 1.5.2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.2%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.2/)) ###\n\n* [Pull 1171](https://github.com/Netflix/Hystrix/pull/1171) Do all histogram latency summarization upfront to minimize storage/operations on them\n* [Pull 1167](https://github.com/Netflix/Hystrix/pull/1167) Javanica: Switch hystrix-javanica to use getExecutionException, which returns Exception object even when command is not executed\n* [Pull 1157](https://github.com/Netflix/Hystrix/pull/1157) Make HystrixMetricsPoller a daemon thread\n* [Pull 1154](https://github.com/Netflix/Hystrix/pull/1154) Remove more unused methods\n* [Pull 1151](https://github.com/Netflix/Hystrix/pull/1151) Remove unused method in HystrixCollapserProperties\n* [Pull 1149](https://github.com/Netflix/Hystrix/pull/1149) Make queue size of MetricJsonListener configurable\n* [Pull 1124](https://github.com/Netflix/Hystrix/pull/1124) Turning down loglevels of metrics streams\n* [Pull 1120](https://github.com/Netflix/Hystrix/pull/1120) Making the HystrixTimeoutException instance per-command, not static\n\n### Version 1.4.25 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.25%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.25/)) ###\n\n* [Pull 1114](https://github.com/Netflix/Hystrix/pull/1114) Make queue size of MetricsJsonListener configurable\n* [Pull 1121](https://github.com/Netflix/Hystrix/pull/1121) HystrixTimeoutException is non-static for better stacktrace\n\nArtifacts: [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.25%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.25/)\n\n### Version 1.5.1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.1%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.1/)) ###\n\n* [Pull 1118](https://github.com/Netflix/Hystrix/pull/1118) Revert #1075.  Return userThreadLatency to metrics, mostly to maintain format compatibility with data streams from 1.4.x\n* [Pull 1116](https://github.com/Netflix/Hystrix/pull/1116) Fix references to underscore.js over HTTPS\n* [Pull 1115](https://github.com/Netflix/Hystrix/pull/1115) Fix LICENSE reference in README\n* [Pull 1111](https://github.com/Netflix/Hystrix/pull/1111) HystrixRequestContext implements Closeable\n\n### Version 1.5.0 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0/)) ###\n\nThe general premise of this release is to make metrics more flexible within Hystrix. See https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring for a deep dive on the new metrics architecture.  The high-level approach is to model metrics directly as a stream, so that Hystrix metrics consumers may aggregate the metrics as they wish. In 1.4.x and prior releases, `HystrixRollingNumber` and `HystrixRollingPercentile` were used to store aggregate command counters and command latencies, respectively.  These are no longer used.  \n\nInstead, new concepts like `HystrixCommandCompletionStream` are present.  These may be consumed by a rolling, summarizing data structure (like `HystrixRollingNumber`), or they may be consumed without any aggregation at all.  This should allow for all metrics processing to move off-box, if you desire to add that piece to your infrastructure.\n\nThis version should be backwards-compatible with v1.4.x.  If you find otherwise, please submit a Hystrix issue as it was unintentional.\n\nThis version also introduces new metric streams: ([configuration](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#configuration-stream) and [Utilization](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#utilization-stream)) have been added, along with a [request-scoped stream](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#request-streams).\n\nArchaius is now a soft-dependency of Hystrix, so you can supply your own configuration mechanism.\n\nSome known semantic changes:\n* Latencies for timeouts and bad-requests are now included in command latency\n* Latency distribution percentiles are now calculated with HdrHistogram library and don't have a max number of elements in the distribution\n* Previously, HealthCounts data allowed reads to see the value in the \"hot\" bucket.  (the one currently being written to).  That does not happen anymore - only full read-only buckets are available for reads.\n* Bucket rolling now happens via Rx background threads instead of unlucky Hystrix command threads.  This makes command performance more predictable.  User-thread latency is now practically indistinguishable from command latency.\n\n### Version 1.4.24 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.24%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.24/)) ###\n\n* [Pull 1113](https://github.com/Netflix/Hystrix/pull/1113) Make HystrixRequestContext implement Closeable\n* [Pull 1112](https://github.com/Netflix/Hystrix/pull/1112) Upgrade to latest Nebula Gradle plugin\n* [Pull 1110](https://github.com/Netflix/Hystrix/pull/1110) Upgrade to RxJava 1.1.1\n* [Pull 1108](https://github.com/Netflix/Hystrix/pull/1108) Javanica HystrixRequestCacheManager should use the concurrency strategy \n\n### Version 1.5.0-rc.5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.5%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.5/)) ###\n\nThis version does not have any known bugs, but is not recommended for production use until 1.5.0.\n\nIncluded changes: \n\n* [Pull 1102](https://github.com/Netflix/Hystrix/pull/1102) Bugfix to null check on HystrixRequestCache context\n\n### Version 1.5.0-rc.4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.4%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.4/)) ###\n\nThis version does not have any known bugs, but is not recommended for production use until 1.5.0.\n\nIncluded changes: \n\n* [Pull 1099](https://github.com/Netflix/Hystrix/pull/1099) Bugfix to get Hystrix dashboard operational again\n\n### Version 1.5.0-rc.3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.3%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.3/)) ###\n\nThis version does not have any known bugs, but is not recommended for production use until 1.5.0.\n\nA few dependency bumps, but the major change here is that Archaius is now a soft dependency of hystrix-core.  Thanks to @agentgt for the PR!. Thanks also to @caarlos0 for the NPE fix in HystrixRequestCache.\n \nIncluded changes: \n\n* [Pull 1079](https://github.com/Netflix/Hystrix/pull/1079) Remove dynamic config lookup in HystrixThreadPool\n* [Pull 1081](https://github.com/Netflix/Hystrix/pull/1081) Cleanup hystrix-javanica BadRequest docs\n* [Pull 1093](https://github.com/Netflix/Hystrix/pull/1093) Fix NPE in HystrixRequestCache when HystrixRequestContext not initialized\n* [Pull 1083](https://github.com/Netflix/Hystrix/pull/1083) Made Archaius a soft dependency of hystrix-core.  It is now possible to run without Archaius and rely on j.u.l.ServiceLoader or system properties only\n* [Pull 1095](https://github.com/Netflix/Hystrix/pull/1095) Upgrade to Nebula netflixoss 3.2.3\n* [Pull 1096](https://github.com/Netflix/Hystrix/pull/1096) Upgrade to RxJava 1.1.1\n* [Pull 1097](https://github.com/Netflix/Hystrix/pull/1097) Fix POM generation by excluding WAR artifacts\n\n### Version 1.5.0-rc.2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.2%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.2/)) ###\n\nThis version does not have any known bugs, but is not recommended for production use until 1.5.0.\n\nThis is mostly a new set of features building on top of Release Candidate 1.  Specifically, some sample streams ([Configuration](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#configuration-stream) and [Utilization](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#utilization-stream)) have been added, along with a [request-scoped stream](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring#request-streams).\n \nIncluded changes: \n\n* [Pull 1050](https://github.com/Netflix/Hystrix/pull/1050) Modular command construction\n* [Pull 1061](https://github.com/Netflix/Hystrix/pull/1061) Sample config/utilization streams, and request-scoped streams\n* [Pull 1064](https://github.com/Netflix/Hystrix/pull/1064) Safer enum references in case mismatched Hystrix jars are deployed together\n* [Pull 1066](https://github.com/Netflix/Hystrix/pull/1066) Layer of abstraction on top of ThreadFactory, so AppEngine can run Hystrix\n* [Pull 1067](https://github.com/Netflix/Hystrix/pull/1067) Decouple sample stream JSON from servlets\n* [Pull 1067](https://github.com/Netflix/Hystrix/pull/1068) Decouple request-scoped stream JSON from servlets\n* [Pull 1075](https://github.com/Netflix/Hystrix/pull/1075) Deprecate userThreadLatency, since it is practically identical to executionLatency now\n\n### Version 1.5.0-rc.1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.1%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.1/)) ###\n\nThis version does not have any known bugs, but *is not* recommended for production use until 1.5.0.\n\nThe general premise of this release is to make metrics more flexible within Hystrix. See https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring for a deep dive on the new metrics architecture.  The high-level view is to make the metrics primitive a stream instead of an aggregate.  In 1.4.x and prior releases, `HystrixRollingNumber` and `HystrixRollingPercentile` were used to store aggregate command counters and command latencies, respectively.  These are no longer used.  \n\nInstead, new concepts like `HystrixCommandCompletionStream` are present.  These may be consumed by a rolling, summarizing data structure (like `HystrixRollingNumber`), or they may be consumed without any aggregation at all.  This should allow for all metrics processing to move off-box, if you desire to add that piece to your infrastructure.\n\nThis version should be backwards-compatible with v1.4.x.  If you find otherwise, please submit a Hystrix issue as it was unintentional.\n\nSome known semantic changes:\n* Latencies for timeouts and bad-requests are now included in command latency\n* Latency distribution percentiles are now calculated with HdrHistogram library and don't have a max number of elements in the distribution\n* Previously, HealthCounts data allowed reads to see the value in the \"hot\" bucket.  (the one currently being written to).  That does not happen anymore - only full read-only buckets are available for reads.\n* Bucket rolling now happens via Rx background threads instead of unlucky Hystrix command threads.  This makes command performance more predictable.  User-thread latency is now practically indistinguishable from command latency.\n\nArtifacts: [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.5.0-rc.1%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.5.0-rc.1/)\n\n### Version 1.4.23 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.23%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.23/)) ###\n\n* [Pull 1032](https://github.com/Netflix/Hystrix/pull/1032) Make number of timer threads a piece of config (with Archaius integration)\n* [Pull 1045](https://github.com/Netflix/Hystrix/pull/1045) Documentation cleanup in HystrixCommandProperties\n* [Pull 1044](https://github.com/Netflix/Hystrix/pull/1044) Add request context and HystrixObservableCommand to command execution JMH tests\n* [Pull 1043](https://github.com/Netflix/Hystrix/pull/1043) HystrixObservableCollapser emits error to each submitter when batch command encounters error\n* [Pull 1039](https://github.com/Netflix/Hystrix/pull/1039) Use thread-safe data structure for storing list of command keys per-thread\n* [Pull 1036](https://github.com/Netflix/Hystrix/pull/1036) Remove redundant ConcurrentHashMap read when getting name from command class\n* [Pull 1035](https://github.com/Netflix/Hystrix/pull/1035) Rename command execution JMH tests\n* [Pull 1034](https://github.com/Netflix/Hystrix/pull/1034) Remove SHORT_CIRCUITED events from health counts calculation \n* [Pull 1027](https://github.com/Netflix/Hystrix/pull/1027) Fix typo in hystrix-examples-webapp documentation\n\n### Version 1.4.22 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.22%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.22/)) ###\n\n* [Pull 1019](https://github.com/Netflix/Hystrix/pull/1019) hystrix-dashboard: Swap magnifying glass logos\n* [Commit 41e9c210f044fe822625acc6e23c5167e56c3f09](https://github.com/Netflix/Hystrix/commit/41e9c210f044fe822625acc6e23c5167e56c3f09) Add OSSMETADATA\n* [Pull 1014](https://github.com/Netflix/Hystrix/pull/1014) Upgrade to RxJava 1.1.0\n* [Pull 1009](https://github.com/Netflix/Hystrix/pull/1009) hystrix-javanica: Upgrade to AspectJ 1.8.6\n* [Pull 1008](https://github.com/Netflix/Hystrix/pull/1008) Add AbstractCommand.getExecutionException\n* [Pull 1006](https://github.com/Netflix/Hystrix/pull/1006) Add Cobertura plugin\n* [Pull 1005](https://github.com/Netflix/Hystrix/pull/1005) Upgrade RxJava to 1.0.17\n* [Pull 1000](https://github.com/Netflix/Hystrix/pull/1000) Fix network-auditor Javadoc\n* [Pull 999](https://github.com/Netflix/Hystrix/pull/999) Upgrade Javassist within hystrix-network-auditor-agent\n* [Pull 992](https://github.com/Netflix/Hystrix/pull/992) hystrix-dashboard: Remove validation error message when adding a stream\n* [Pull 977](https://github.com/Netflix/Hystrix/pull/977) hystrix-javanica support for Observable command\n\n### Version 1.4.21 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.21%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.21/)) ###\n\n* [Pull 978](https://github.com/Netflix/Hystrix/pull/978) Upgrade commons-collections to 3.2.2\n* [Pull 959](https://github.com/Netflix/Hystrix/pull/959) Support multiple metric streams in hystrix-dashboard\n* [Pull 976](https://github.com/Netflix/Hystrix/pull/976) Prevent execution observable from running when hook throws an error in onXXXStart \n* [Pull 972](https://github.com/Netflix/Hystrix/pull/972) Mark servlet-api dependency as 'provided'\n* [Pull 968](https://github.com/Netflix/Hystrix/pull/968) Add defaultSetter() to properties classes to workaround GROOVY-6286\n\n### Version 1.4.20 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.20%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.20/)) ###\n\n* [Pull 965](https://github.com/Netflix/Hystrix/pull/965) Upgrade Nebula Gradle plugin\n* [Pull 962](https://github.com/Netflix/Hystrix/pull/962) Javanica: Support for async commands\n* [Pull 960](https://github.com/Netflix/Hystrix/pull/960) Avoid Clojure reflection in hystrix-clj\n* [Pull 957](https://github.com/Netflix/Hystrix/pull/957) Javanica: Fix threadpool properties\n* [Pull 956](https://github.com/Netflix/Hystrix/pull/956) Upgrade JMH from 1.10.3 to 1.11.1\n* [Pull 945](https://github.com/Netflix/Hystrix/pull/945) Javanica: Compile-time weaving support\n* [Pull 952](https://github.com/Netflix/Hystrix/pull/952) Tolerate lack of RequestContext better for custom concurrency strategies\n* [Pull 947](https://github.com/Netflix/Hystrix/pull/947) Upgrade RxNetty to 0.4.12 for RxNetty metrics stream\n* [Pull 946](https://github.com/Netflix/Hystrix/pull/946) More extension-friendly Yammer metrics publisher\n* [Pull 944](https://github.com/Netflix/Hystrix/pull/944) Fix generated POM to include dependencies in 'compile' scope\n* [Pull 942](https://github.com/Netflix/Hystrix/pull/942) Fix metrics stream fallbackEmit metric\n* [Pull 941](https://github.com/Netflix/Hystrix/pull/941) Add FALLBACK_MISSING event type and metric\n\n### Version 1.4.19 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.19%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.19/)) ###\n\nThis version should be the exact same as 1.4.20, but suffered problems during the publishing process.  Please use 1.4.20 instead.\n\n### Version 1.4.18 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.18%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.18/)) ###\n\n* [Pull 934](https://github.com/Netflix/Hystrix/pull/934) Remove duplicate EventSource from dashboard\n* [Pull 931](https://github.com/Netflix/Hystrix/pull/931) Make HystrixTimeoutException public\n* [Pull 930](https://github.com/Netflix/Hystrix/pull/930) Support collapser metrics in HystrixMetricPublisher implementations\n* [Pull 927](https://github.com/Netflix/Hystrix/pull/927) Dashboard fix to isCircuitBreakerOpen\n\n### Version 1.4.17 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.17%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.17/)) ###\n\n* [Pull 924](https://github.com/Netflix/Hystrix/pull/924) Dashboard protection against XSS\n* [Pull 923](https://github.com/Netflix/Hystrix/pull/923) Upgrade to RxJava 1.0.14\n* [Pull 922](https://github.com/Netflix/Hystrix/pull/922) Add DEBUG tag to Servo rolling counter and made it a GaugeMetric\n\n### Version 1.4.16 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.16%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.16/)) ###\n\n* [Pull 917](https://github.com/Netflix/Hystrix/pull/917) Better version of making servo-metrics-publisher extension-friendly\n* [Pull 912](https://github.com/Netflix/Hystrix/pull/912) Only look up if HystrixRequestCache is enabled once per HystrixObservableCollapser-invocation\n* [Pull 911](https://github.com/Netflix/Hystrix/pull/911) Unit test for large threadpool/small queue case in command execution\n* [Pull 910](https://github.com/Netflix/Hystrix/pull/910) Make servo-metrics-publisher more extension-friendly\n* [Pull 905](https://github.com/Netflix/Hystrix/pull/905) HystrixObservableCollapser examples\n* [Pull 902](https://github.com/Netflix/Hystrix/pull/902) Cleanup HystrixObservableCollapser unit tests\n* [Pull 900](https://github.com/Netflix/Hystrix/pull/900) Remove commons-collections dependency from hystrix-javanica\n* [Pull 897](https://github.com/Netflix/Hystrix/pull/897) Fix missing null check in hystrix-javanica HystrixCacheKeyGenerator\n\n### Version 1.4.15 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.15%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.15/)) ###\n\n* [Pull 890](https://github.com/Netflix/Hystrix/pull/890) Allow multiple responses per collapser argument.  No semantic change for HystrixCollapser, but a bugfix to HystrixObservableCollapser\n* [Pull 892](https://github.com/Netflix/Hystrix/pull/892) Cache Setter in MultithreadedMetricsPerfTest\n* [Pull 891](https://github.com/Netflix/Hystrix/pull/891) Add request context to command JMH tests\n* [Pull 889](https://github.com/Netflix/Hystrix/pull/889) Replace subscribe() in RequestBatch with unsafeUnsubscribe()\n* [Pull 887](https://github.com/Netflix/Hystrix/pull/887) Only look up if HystrixRequestCache is enabled once per collapser-invocation\n* [Pull 885](https://github.com/Netflix/Hystrix/pull/885) Only look up if HystrixRequestCache is enabled once per command-invocation\n* [Pull 876](https://github.com/Netflix/Hystrix/pull/876) Report BAD_REQUEST to HystrixRequestLog\n* [Pull 861](https://github.com/Netflix/Hystrix/pull/861) Make hystrix-javanica OSGI-compliant\n* [Pull 856](https://github.com/Netflix/Hystrix/pull/856) Add missing licenses\n* [Pull 855](https://github.com/Netflix/Hystrix/pull/855) Save allocation if using a convenience constructor for HystrixCommand\n* [Pull 853](https://github.com/Netflix/Hystrix/pull/853) Run Travis build in a container\n* [Pull 848](https://github.com/Netflix/Hystrix/pull/848) Unit tests to demonstrate HystrixRequestLog was not experiencing data races\n\n### Version 1.4.14 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.14%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.14/)) ###\n\n* [Pull 852](https://github.com/Netflix/Hystrix/pull/852) Fix hystrix-clj that was blocking http://dev.clojure.org/jira/browse/CLJ-1232\n* [Pull 849](https://github.com/Netflix/Hystrix/pull/849) Unit tests for HystrixCommands that are part of a class hierarchy with other HystrixCommands\n\n### Version 1.4.13 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.13%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.13/)) ###\n\n* [Pull 839](https://github.com/Netflix/Hystrix/pull/839) Fix typo in hystrix-dashboard js\n* [Pull 838](https://github.com/Netflix/Hystrix/pull/838) Add back unit tests for Hystrix class and its reset() method in particular\n* [Pull 837](https://github.com/Netflix/Hystrix/pull/837) Upgrade to RxJava 1.0.13\n* [Pull 830](https://github.com/Netflix/Hystrix/pull/830) Add validation for rollingCountBadRequest in hystrix-dashboard\n\n### Version 1.4.12 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.12%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.12/)) ###\n\n* [Pull 826](https://github.com/Netflix/Hystrix/pull/826) Safely handle negative input for delay parameter to metrics stream servlet\n* [Pull 825](https://github.com/Netflix/Hystrix/pull/825) Only check bucket properties at HystrixRollingNumber construction\n* [Pull 824](https://github.com/Netflix/Hystrix/pull/824) Only check bucket properties at HystrixRollingPercentile construction\n* [Pull 823](https://github.com/Netflix/Hystrix/pull/823) Fix half hidden mean metric in Hystrix Dashboard because of container height\n* [Pull 818](https://github.com/Netflix/Hystrix/pull/818) Only check maxQueueSize value at thread pool construction\n\n### Version 1.4.11 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.11%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.11/)) ###\n\n* [Pull 814](https://github.com/Netflix/Hystrix/pull/814) Upgrade to RxJava 1.0.12\n* [Pull 813](https://github.com/Netflix/Hystrix/pull/813) Output something when Hystrix falls back on recoverable java.lang.Error\n* [Pull 812](https://github.com/Netflix/Hystrix/pull/812) Fixing overload functions in hystrix-clj\n* [Pull 808](https://github.com/Netflix/Hystrix/pull/808) Update Hystrix Metrics Stream README\n\n### Version 1.4.10 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.10%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.10/)) ###\n\n* [Pull 804](https://github.com/Netflix/Hystrix/pull/804) Fix memory leak by switching back to AtomicIntegerArray for HystrixRollingPercentile\n\n### Version 1.4.9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.9%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.9/)) ###\n\n* [Pull 799](https://github.com/Netflix/Hystrix/pull/799) Fix thread-safety of writes to HystrixRollingPercentile\n\n### Version 1.4.8 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.8%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.8/)) ###\n\n* [Pull 797](https://github.com/Netflix/Hystrix/pull/797) Move all histogram reads to a single-threaded path.\n* [Pull 794](https://github.com/Netflix/Hystrix/pull/794) Allow dashboard connection on 'Enter' keypress\n* [Pull 787](https://github.com/Netflix/Hystrix/pull/787) Reject requests after metrics-event-stream servlet shutdown\n* [Pull 785](https://github.com/Netflix/Hystrix/pull/785) Update metrics package from com.codahale.metrics to io.dropwizard.metrics\n\n### Version 1.4.7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.7%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.7/)) ###\n\n* [Pull 783](https://github.com/Netflix/Hystrix/pull/783) Upgrade to RxJava 1.0.10\n* [Pull 781](https://github.com/Netflix/Hystrix/pull/781) Shorten collapser stress test to avoid OOM in Travis\n* [Pull 780](https://github.com/Netflix/Hystrix/pull/780) Allow hooks to throw exceptions and not corrupt internal Hystrix state\n* [Pull 779](https://github.com/Netflix/Hystrix/pull/779) Use HdrHistogram for capturing latencies\n* [Pull 778](https://github.com/Netflix/Hystrix/pull/778) Run jmh using more forks and fewer iterations/fork\n* [Pull 776](https://github.com/Netflix/Hystrix/pull/776) Add Bad requests to Hystrix dashboard\n* [Pull 775](https://github.com/Netflix/Hystrix/pull/775) Add counters for number of commands, thread pools, groups\n* [Pull 774](https://github.com/Netflix/Hystrix/pull/774) Add global concurrent Hystrix threads counter\n\n### Version 1.4.6 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.6%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.6/)) ###\n\n* [Pull 772](https://github.com/Netflix/Hystrix/pull/772) Add try-catch to all hook invocations\n* [Pull 773](https://github.com/Netflix/Hystrix/pull/773) Move threadPool field to end of metrics stream\n* [Pull 770](https://github.com/Netflix/Hystrix/pull/770) Fix AbstractCommand.isCircuitBreakerOpen() return value when circuit is forced open or closed\n* [Pull 769](https://github.com/Netflix/Hystrix/pull/769) Add threadPool to command metrics in event stream\n* [Pull 767](https://github.com/Netflix/Hystrix/pull/767) JMH upgrade and multithreaded benchmark\n\n### Version 1.4.5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.5%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.5/)) ###\n\n* [Pull 764](https://github.com/Netflix/Hystrix/pull/764) Upgrade RxJava from 1.0.7 to 1.0.9\n* [Pull 763](https://github.com/Netflix/Hystrix/pull/763) Upgrade Jackson for hystrix-metrics-event-stream from 1.9.2 to 2.5.2\n* [Pull 760](https://github.com/Netflix/Hystrix/pull/760) Set Hystrix-created threads to be daemon\n* [Pull 757](https://github.com/Netflix/Hystrix/pull/757) Update RxNetty version in hystrix-rx-netty-metrics-stream from 0.3.8 to 0.4.7\n* [Pull 755](https://github.com/Netflix/Hystrix/pull/755) Improve Javadoc for HystrixThreadPoolProperties.Setter\n* [Pull 754](https://github.com/Netflix/Hystrix/pull/754) Only fire onFallbackStart/onFallbackError hooks when a user-supplied fallback is invoked\n* [Pull 753](https://github.com/Netflix/Hystrix/pull/753) Add timeout to dashboard for semaphore commands\n* [Pull 750](https://github.com/Netflix/Hystrix/pull/750) First pass at jmh performance benchmarking\n* [Pull 748](https://github.com/Netflix/Hystrix/pull/748) Fix return value of HystrixCircuiBreakerImpl.isOpen when it loses a race to open a circuit\n* [Pull 746](https://github.com/Netflix/Hystrix/pull/746) Improve Javadoc for HystrixCommandProperties.Setter\n\n\n### Version 1.4.4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.4%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.4/)) ###\n\n* [Pull 743](https://github.com/Netflix/Hystrix/pull/743) Proper Javadoc deprecation for command timeouts being thread-specific\n* [Pull 742](https://github.com/Netflix/Hystrix/pull/742) Add flag to disable command timeouts\n* [Pull 741](https://github.com/Netflix/Hystrix/pull/741) Bugfix to java.lang.Error handling\n* [Pull 735](https://github.com/Netflix/Hystrix/pull/735) (Javanica) BatchHystrixCommand\n* [Pull 739](https://github.com/Netflix/Hystrix/pull/739) Mark some java.lang.Errors as unrecoverable and never trigger fallback\n* [Pull 738](https://github.com/Netflix/Hystrix/pull/738) Filter out thread pools with no thread activity from hystrics-metrics-event-stream\n* [Pull 732](https://github.com/Netflix/Hystrix/pull/732) Comment out flaky unit test\n\n### Version 1.4.3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.3%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.3/)) ###\n\n* [Pull 731](https://github.com/Netflix/Hystrix/pull/731) Revert to Java 6\n* [Pull 728](https://github.com/Netflix/Hystrix/pull/728) Add semaphore-rejected count to dashboard\n* [Pull 711](https://github.com/Netflix/Hystrix/pull/711) Use Archaius for plugin registration\n* [Pull 671](https://github.com/Netflix/Hystrix/pull/671) Stop passing Transfer-Encoding header when streaming metrics\n\n### Version 1.4.2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.2%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.2/)) ###\n\n* [Pull 723](https://github.com/Netflix/Hystrix/pull/723) Fixed Javanica issue where annotation appeared in superclasses\n* [Pull 727](https://github.com/Netflix/Hystrix/pull/727) Fixed TravisCI issue by raising timeout in fallback rejection unit test\n* [Pull 724](https://github.com/Netflix/Hystrix/pull/724) Fixed backwards-incompatibility where using a custom HystrixConcurrencyStrategy forced use of a non-null HystrixRequestContext\n* [Pull 717](https://github.com/Netflix/Hystrix/pull/717) Added error message to dashboard HTML when connection to metrics source fails\n\n### Version 1.4.1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.1%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.1/)) ###\n\n* [Pull 716](https://github.com/Netflix/Hystrix/pull/716) Fixed backwards-incompatibility where .execute(), .queue(), .observe(), .toObservable() were all made final in 1.4.0\n\n### Version 1.4.0 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.0/)) ###\n\nThis version adds HystrixObservableCommand and implements both it and HystrixCommand in terms of [Observables](https://github.com/ReactiveX/RxJava).  \n\nA HystrixObservableCommand allows for fully non-blocking commands that can be composed as part of a larger Observable chain.  See [the wiki](https://github.com/Netflix/Hystrix/wiki/How-To-Use#reactive-commands) for more details on usage.  Here's an example (using Java 8):\n\n```java\npublic class ObservableHttpCommand extends HystrixObsverableCommand<BackendResponse> {\n\n@Override\nprotected Observable<BackendResponse> construct() {\n    return httpClient.submit(HttpClientRequest.createGet(\"/mock.json?numItems=\" + numItems))\n        .flatMap((HttpClientResponse<ByteBuf> r) -> r.getContent()\n        .map(b -> BackendResponse.fromJson(new ByteBufInputStream(b))));\n    }\n\n@Override\nprotected Observable<BackendResponse> resumeWithFallback() {\n    return Observable.just(new BackendResponse(0, numItems, new String[] {}));\n}}\n\n```\n\nBecause an Observable represents a stream of data, your HystrixObservableCommand may now return a stream of data, and supply a stream of data as a fallback.  The methods to do so are `construct()` and `resumeWithFallback()`, respectively.  All other aspects of the Hystrix state machine work the same in a HystrixCommand.  See [this wiki page](https://github.com/Netflix/Hystrix/wiki/How-it-Works#flow-chart) for a diagram of this state machine.\n\nThe public API of HystrixCommand is unchanged, though the internals have significantly changed.  Some bugfixes are now possible that affect Hystrix semantics:\n\n* Timeouts now apply to semaphore-isolated commands as well as thread-isolated commands.  Before 1.4.x, semaphore-isolated commands could not timeout.  They now have a timeout registered on another (HystrixTimer) thread, which triggers the timeout flow.  If you use semaphore-isolated commands, they will now see timeouts.  As all HystrixCommands have a [default timeout](https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds), this potentially affects all semaphore-isolated commands.\n* Timeouts now fire on `HystrixCommand.queue()`, even if the caller never calls `get()` on the resulting Future.  Before 1.4.x, only calls to `get()` triggered the timeout mechanism to take effect.\n\nYou can see more in-depth examples of how the new functionality of Hystrix 1.4 is used at [Netflix/ReactiveLab](https://github.com/Netflix/ReactiveLab).\n\nYou can learn more about Observables and RxJava at [Netflix/RxJava](https://github.com/ReactiveX/RxJava).\n\nAs this was a major refactoring of Hystrix internals, we (Netflix) have run a release candidate of Hystrix 1.4 in canaries and production over the last month to gain confidence.\n\n* [Pull 701](https://github.com/Netflix/Hystrix/pull/701) Fix Javadoc warnings\n* [Pull 700](https://github.com/Netflix/Hystrix/pull/700) Example code for publishing to Graphite\n\n### Version 1.4.0 Release Candidate 9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-rc.9%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.0-rc.9/)) ###\n_NOTE: This code is believed to be production worthy.  As of now, there are no known bugs preventing this becoming 1.4.0.  Please report any design issues/questions, bugs, or any observations about this release to the [Issues](https://github.com/Netflix/Hystrix/issues) page._\n\n* [Pull 697](https://github.com/Netflix/Hystrix/pull/697) Add execution event for FALLBACK_REJECTION and unit tests\n* [Pull 696](https://github.com/Netflix/Hystrix/pull/696) Upgrade to RxJava 1.0.7\n* [Pull 694](https://github.com/Netflix/Hystrix/pull/694) Make execution timeout in HystrixCommandProperties work in the case when classes extend HystrixCommandProperties\n* [Pull 693](https://github.com/Netflix/Hystrix/pull/693) Hystrix Dashboard sorting issue\n\n### Version 1.4.0 Release Candidate 8 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-rc.8%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.0-rc.8/)) ###\n_NOTE: This code is believed to be production worthy.  As of now, there are no known bugs preventing this becoming 1.4.0.  Please report any design issues/questions, bugs, or any observations about this release to the [Issues](https://github.com/Netflix/Hystrix/issues) page._\n\n* [Pull 691](https://github.com/Netflix/Hystrix/pull/691) HystrixCommandTest test with large number of semaphores\n* [Pull 690](https://github.com/Netflix/Hystrix/pull/690) Add back ExceptionThreadingUtility\n* [Pull 688](https://github.com/Netflix/Hystrix/pull/688) Add metrics for EMIT and FALLBACK_EMIT\n* [Pull 687](https://github.com/Netflix/Hystrix/pull/687) Fixed issue where fallback rejection was also incrementing fallback failure metric\n* [Pull 686](https://github.com/Netflix/Hystrix/pull/686) HystrixCommandTest Unit test refactoring\n* [Pull 683](https://github.com/Netflix/Hystrix/pull/683) Add and Deprecate pieces of execution hook API to be more consistent\n* [Pull 681](https://github.com/Netflix/Hystrix/pull/681) Add cache hit execution hook\n* [Pull 680](https://github.com/Netflix/Hystrix/pull/680) Add command rejection metrics for HystrixThreadPools\n\n\n### Version 1.4.0 Release Candidate 7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-rc.7%22), [Bintray](https://bintray.com/netflixoss/maven/Hystrix/1.4.0-rc.7/)) ###\nNOTE: This code is believed to be production worthy.  As of now, there are no known bugs preventing this becoming 1.4.0.  Please report any design issues/questions, bugs, or any observations about this release to the [Issues](https://github.com/Netflix/Hystrix/issues) page\n\n* [Pull 678](https://github.com/Netflix/Hystrix/pull/678) Fix current concurrent execution count\n* [Pull 676](https://github.com/Netflix/Hystrix/pull/676) Add test to confirm that bad requests do not affect circuit breaker's computed error percentage\n* [Pull 675](https://github.com/Netflix/Hystrix/pull/675) Deprecate method names for executionTimeout that are thread-specific\n* [Pull 672](https://github.com/Netflix/Hystrix/pull/672) Limit the thread-interrupt behavior to occur only on timeouts\n* [Pull 669](https://github.com/Netflix/Hystrix/pull/669) Added unit tests to demonstrate non-blocking semaphore timeout\n* [Pull 667](https://github.com/Netflix/Hystrix/pull/667) Added rolling max counter for command execution\n* [Pull 666](https://github.com/Netflix/Hystrix/pull/666) Added missing licenses\n* [Pull 665](https://github.com/Netflix/Hystrix/pull/665) Added comment to HystrixConcurrencyStrategy about non-idempotency of strategy application\n* [Pull 647](https://github.com/Netflix/Hystrix/pull/647) Tie command property to thread interrupt\n* [Pull 645](https://github.com/Netflix/Hystrix/pull/645) Remove incorrect reference to async timeout\n* [Pull 644](https://github.com/Netflix/Hystrix/pull/644) Add RequestCollapser metrics to Yammer Metrics Publisher\n* [Pull 643](https://github.com/Netflix/Hystrix/pull/643) Stress-test HystrixObservalbeCollapser\n* [Pull 642](https://github.com/Netflix/Hystrix/pull/642) Fix flakiness of HystrixObservableCommandTest.testRejectedViaSemaphoreIsolation\n* [Pull 641](https://github.com/Netflix/Hystrix/pull/641) Fix flakiness of testSemaphorePermitsInUse\n* [Pull 608](https://github.com/Netflix/Hystrix/pull/608) Make HystrixObservableCommand handle both sync and async exceptions\n* [Pull 607](https://github.com/Netflix/Hystrix/pull/607) Upgrade RxJava from 1.0.4 to 1.0.5\n* [Pull 604](https://github.com/Netflix/Hystrix/pull/604) Added EMIT and FALLBACK_EMIT event types that get emitted in HystrixObservableCommand\n* [Pull 599](https://github.com/Netflix/Hystrix/pull/599) Added metrics to HystrixObservableCollapser\n* [Pull 596](https://github.com/Netflix/Hystrix/pull/596) Fixed HystrixContextScheduler to conform with RxJava Worker contract\n* [Pull 583](https://github.com/Netflix/Hystrix/pull/583) Style and consistency fixes\n* [Pull 582](https://github.com/Netflix/Hystrix/pull/582) Add more unit tests for non-blocking HystrixCommand.queue()\n* [Pull 580](https://github.com/Netflix/Hystrix/pull/580) Unit test to demonstrate fixed non-blocking timeout for HystrixCommand.queue()\n* [Pull 579](https://github.com/Netflix/Hystrix/pull/579) Remove synchronous timeout\n* [Pull 577](https://github.com/Netflix/Hystrix/pull/577) Upgrade language level to Java7\n* [Pull 576](https://github.com/Netflix/Hystrix/pull/576) Add request collapser metrics\n* [Pull 573](https://github.com/Netflix/Hystrix/pull/573) Fix link to CHANGELOG.md in README.md\n* [Pull 572](https://github.com/Netflix/Hystrix/pull/572) Add bad request metrics at the command granularity\n* [Pull 567](https://github.com/Netflix/Hystrix/pull/567) Comment out flaky unit-tests\n* [Pull 566](https://github.com/Netflix/Hystrix/pull/566) Fix hardcoded groupname in CodaHale metrics publisher\n* [Commit 6c08d9](https://github.com/Netflix/Hystrix/commit/6c08d90fd10a947bdbee81afc9c0f866d1f33eef) Bumped nebula.netflixoss from 2.2.3 to 2.2.5\n* [Pull 562](https://github.com/Netflix/Hystrix/pull/562) Build changes to nebula.netflixoss (initially submitted as [Pull 469](https://github.com/Netflix/Hystrix/pull/469))\n\t\n\t\n### Version 1.4.0 Release Candidate 6 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC6%22)) ###\n\n_NOTE: This code is believed to be production worthy but is still a \"Release Candidate\" until [these possible functional or design issues are resolved](https://github.com/Netflix/Hystrix/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.4.0-RC7)._\n* [Pull 534](https://github.com/Netflix/Hystrix/pull/534) Bump RxJava to 1.0.4\n* [Pull 532](https://github.com/Netflix/Hystrix/pull/532) Hystrix-Clojure: Fix typo\n* [Pull 531](https://github.com/Netflix/Hystrix/pull/531) Move onThreadStart execution hook after check that wrapping thread timed out \n* [Pull 530](https://github.com/Netflix/Hystrix/pull/530) Add shutdown hook to metrics servlet for WebSphere\n* [Pull 527](https://github.com/Netflix/Hystrix/pull/527) Creating a synthetic exception in the semaphore execution and short-circuited case\n* [Pull 526](https://github.com/Netflix/Hystrix/pull/526) Move onRunSuccess/onRunError and thread-pool book-keeping to Hystrix thread\n* [Pull 524](https://github.com/Netflix/Hystrix/pull/524) Change calls from getExecutedCommands() to getAllExecutedCommands()\n* [Pull 516](https://github.com/Netflix/Hystrix/pull/516) Updated HystrixServoMetricsPublisher initalization of singleton\n* [Pull 489](https://github.com/Netflix/Hystrix/pull/489) Javanica: Request Caching\n* [Pull 512](https://github.com/Netflix/Hystrix/pull/512) Add execution hook Javadoc\n* [Pull 511](https://github.com/Netflix/Hystrix/pull/511) Fix missing onComplete hook call when command short-circuits and missing onRunSuccess hook call in thread-timeout case\n* [Pull 466](https://github.com/Netflix/Hystrix/pull/466) Add unit tests to HystrixCommand and HystrixObservableCommand\n* [Pull 465](https://github.com/Netflix/Hystrix/pull/465) Handle error in construction of HystrixMetricsPoller\n* [Pull 457](https://github.com/Netflix/Hystrix/pull/457) Fixing resettability of HystrixMetricsPublisherFactory\n* [Pull 451](https://github.com/Netflix/Hystrix/pull/451) Removed ExceptionThreadingUtility\n* [Pull 366](https://github.com/Netflix/Hystrix/pull/366) Added support to get command start time in Nanos\n* [Pull 456](https://github.com/Netflix/Hystrix/pull/456) Allow hooks to generate HystrixBadRequestExceptions that get handled appropriately\n* [Pull 454](https://github.com/Netflix/Hystrix/pull/454) Add tests around HystrixRequestLog in HystrixObservableCommand\n* [Pull 453](https://github.com/Netflix/Hystrix/pull/453) Resettable command and thread pool defaults\n* [Pull 452](https://github.com/Netflix/Hystrix/pull/452) Make HystrixPlugins resettable\n* [Pull 450](https://github.com/Netflix/Hystrix/pull/450) Add fallback tests to HystrixObservableCommand\n* [Pull 449](https://github.com/Netflix/Hystrix/pull/449) Move thread completion bookkeeping to end of chain\n* [Pull 447](https://github.com/Netflix/Hystrix/pull/447) Synchronous queue fix\n* [Pull 376](https://github.com/Netflix/Hystrix/pull/376) Javanica README cleanup\n* [Pull 378](https://github.com/Netflix/Hystrix/pull/378) Exection hook call sequences (based on work submitted in [Pull 327](https://github.com/Netflix/Hystrix/pull/327))\n* [Pull 374](https://github.com/Netflix/Hystrix/pull/374) RequestBatch logging\n* [Pull 371](https://github.com/Netflix/Hystrix/pull/371) Defer creation of IllegalStateException in collapser flow (based on work submitted in [Pull 264](https://github.com/Netflix/Hystrix/pull/264))\n* [Pull 369](https://github.com/Netflix/Hystrix/pull/369) Added basic auth to Hystrix Dashboard (based on work submitted in [Pull 336](https://github.com/Netflix/Hystrix/pull/336))\n* [Pull 367](https://github.com/Netflix/Hystrix/pull/367) Added thread pool metrics back to execution flow (based on test submitted in [Pull 339](https://github.com/Netflix/Hystrix/pull/339))\n* [Pull 365](https://github.com/Netflix/Hystrix/pull/365) Fix Javadoc for HystrixCommand.Setter\n* [Pull 364](https://github.com/Netflix/Hystrix/pull/364) Upgrade servo to 0.7.5\n* [Pull 362](https://github.com/Netflix/Hystrix/pull/362) Fixed hystrix-rxnetty-metrics-stream unit tests\n* [Pull 359](https://github.com/Netflix/Hystrix/pull/359) Fixed Javanica unit tests\n* [Pull 361](https://github.com/Netflix/Hystrix/pull/361) Race condition when creating HystrixThreadPool (initially submitted as [Pull 270](https://github.com/Netflix/Hystrix/pull/270))\n* [Pull 358](https://github.com/Netflix/Hystrix/pull/358) Fixed Clojure unit tests that failed with RxJava 1.0\n* [Commit 2edcd5](https://github.com/Netflix/Hystrix/commit/2edcd578194849a1c2f5acd73a2e6f10ebfdd112) Upgrade to core-metrics 3.0.2\n* [Pull 310](https://github.com/Netflix/Hystrix/pull/310) Osgi-ify hystrix-core, hystrix-examples\n* [Pull 340](https://github.com/Netflix/Hystrix/pull/340) Race condition when creating HystrixThreadPool\n* [Pull 343](https://github.com/Netflix/Hystrix/pull/343) Added 3 new constructors for common command setup\n* [Pull 347](https://github.com/Netflix/Hystrix/pull/347) Javanica: Allow for @HystrixCommand to be used on parameterized return type\n* [Pull 353](https://github.com/Netflix/Hystrix/pull/353) Fixing a hystrix-examples compilation failure\n* [Pull 338](https://github.com/Netflix/Hystrix/pull/338) API Changes after design review of [Issue 321](https://github.com/Netflix/Hystrix/issues/321)\n* [Pull 344](https://github.com/Netflix/Hystrix/pull/344) Upgrade to Gradle 1.12 \n* [Pull 334](https://github.com/Netflix/Hystrix/pull/334) Javanica: Hystrix Error Propagation \n* [Pull 326](https://github.com/Netflix/Hystrix/pull/326) Javanica: Added support for setting threadPoolProperties through @HystrixCommand annotation\n* [Pull 318](https://github.com/Netflix/Hystrix/pull/318) HystrixAsyncCommand and HystrixObservableCommand\n* [Pull 316](https://github.com/Netflix/Hystrix/pull/316) Add support for execution.isolation.semaphore.timeoutInMilliseconds\n\n### Version 1.3.20 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.20%22)) ###\n* [Pull 533] (https://github.com/Netflix/Hystrix/pull/533) Upgrade to RxJava 1.0.4\n* [Pull 528] (https://github.com/Netflix/Hystrix/pull/528) Pass RuntimeException to onError hook in semaphore-rejection and short-circuit cases, instead of null\n* [Pull 520] (https://github.com/Netflix/Hystrix/pull/520) More unit tests for hook ordering\n* [Commit 61b77c] (https://github.com/Netflix/Hystrix/commit/61b77c305bda6dbd4dc8c86445b4a6670f981845) Fix flow where ExecutionHook.onComplete was called twice\n* [Commit a5e52a] (https://github.com/Netflix/Hystrix/commit/a5e52a6d29cd911c1e14ec107a875a9343472db5) Add call to ExecutionHook.onError in HystrixBadRequestException flow\n* [Commit cec25e] (https://github.com/Netflix/Hystrix/commit/cec25ed7c6f10c4c59189b443bda844fa39043d6) Fix hook ordering assertions\n* [Pull 508] (https://github.com/Netflix/Hystrix/pull/508) Backport of [Pull 327] (https://github.com/Netflix/Hystrix/pull/327) from master: Add hook assertions to unit tests\n* [Pull 507] (https://github.com/Netflix/Hystrix/pull/507) Fix hystrix-clj unit tests\n* [Commit 62be49] (https://github.com/Netflix/Hystrix/commit/62be49465ae418509814fd195081ef7611eb6015) RxJava 1.0.2\n\n### Version 1.3.19 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.19%22)) ###\n\n* [Pull 348](https://github.com/Netflix/Hystrix/pull/348) Javanica: Allow for @HystrixCommand to be used on parameterized return type\n* [Pull 329](https://github.com/Netflix/Hystrix/pull/329) Javanica: allowing configuration of threadPoolProperties through @HystrixCommand annotation\n\n### Version 1.4.0 Release Candidate 5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC5%22)) ###\n\n_NOTE: This code is believed to be production worthy but is still a \"Release Candidate\" until [these possible functional or design issues are resolved](https://github.com/Netflix/Hystrix/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.4)._\n\n* [Pull 314](https://github.com/Netflix/Hystrix/pull/314) RxJava 0.20 and Remove Deprecated Usage\n* [Pull 307](https://github.com/Netflix/Hystrix/pull/307) Dashboard: Avoid NPE when 'origin' parameter not present\n\n### Version 1.3.18 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.18%22)) ###\n\n* [Pull 305](https://github.com/Netflix/Hystrix/pull/305) Removing deprecated RxJava usage\n\n### Version 1.3.17 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.17%22)) ###\n\n* [Pull 291](https://github.com/Netflix/Hystrix/pull/291) String optimization for HystrixRequestLog\n* [Pull 296](https://github.com/Netflix/Hystrix/pull/296) Fix Premature Unsubscribe Bug\n* [Commit 47122e](https://github.com/Netflix/Hystrix/commit/1268454ec4381b6ae121cac1675205484847122e) RxJava 0.20.1\n\n### Version 1.4.0 Release Candidate 4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC4%22)) ###\n\n_NOTE: This code is NOT considered production worthy yet, hence the \"Release Candidate\" status._\n\nThis fixes some bugs and changes the `HystrixObservableCollapser` signature to support `Observable` batches.\n\n* [Pull 256](https://github.com/Netflix/Hystrix/pull/256) Fix Race Condition on Timeout\n* [Pull 261](https://github.com/Netflix/Hystrix/pull/261) New signature for HystrixObservableCollapser\n* [Pull 254](https://github.com/Netflix/Hystrix/pull/254) Remove jsr305 Dependency\n* [Pull 260](https://github.com/Netflix/Hystrix/pull/260) RxJava 0.18.2\n* [Pull 253](https://github.com/Netflix/Hystrix/pull/253) Handling InterruptedExceptions in the HystrixMetricsStreamServlet\n\n### Version 1.4.0 Release Candidate 3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC3%22)) ###\n\n_NOTE: This code is NOT considered production worthy yet, hence the \"Release Candidate\" status._\n\nThis adds non-blocking support to the collapser via the `HystrixObservableCollapser` type, fixes some bugs and upgrades to RxJava 0.18.\n\n* [Pull 245](https://github.com/Netflix/Hystrix/pull/245) HystrixObservableCollapser\n* [Pull 246](https://github.com/Netflix/Hystrix/pull/246) RxJava 0.18\n* [Pull 250](https://github.com/Netflix/Hystrix/pull/250) Tripped CircuitBreaker Wouldn't Close Under Contention\n* [Pull 243](https://github.com/Netflix/Hystrix/pull/243) Update servo to 0.6\n* [Pull 240](https://github.com/Netflix/Hystrix/pull/240) Add missing reset for CommandExecutionHook in HystrixPlugins.UnitTest\n* [Pull 244](https://github.com/Netflix/Hystrix/pull/244) Javanica: Cleaner error propagation \n\n\n### Version 1.4.0 Release Candidate 2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC2%22)) ###\n\n_NOTE: This code is NOT considered production worthy yet, hence the \"Release Candidate\" status._\n\nThis fixes a bug found in Release Candidate 1 that caused the semaphore limits to be applied when thread isolation was chosen.\n\nIt also stops scheduling callbacks onto new threads and lets the Hystrix threads perform the callbacks.\n\n* [Pull 238](https://github.com/Netflix/Hystrix/pull/238) Fix for Semaphore vs Thread Isolation Bug\n* [Pull 230](https://github.com/Netflix/Hystrix/pull/230) Javanica Module: Added support for Request Cache and Reactive Execution\n\n\n### Version 1.4.0 Release Candidate 1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.4.0-RC1%22)) ###\n\nThis is the first release candidate of 1.4.0 that includes `HystrixObservableCommand` ([Source](https://github.com/Netflix/Hystrix/blob/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java)) that supports bulkheading asynchronous, non-blocking sources.\n\n_NOTE: This code is NOT considered production worthy yet, hence the \"Release Candidate\" status._\n\n_It has run for 1 day on a single machine taking production traffic at Netflix. This is sufficient for us to proceed to a release candidate for official canary testing, but we intend to test for a week or two before doing a final release._\n\nHere is a very basic example using Java 8 to make an HTTP call via Netty and receives a stream of chunks back:\n\n```java\n\n    public static void main(String args[]) {\n        HystrixObservableCommand<String> command = bulkheadedNetworkRequest(\"www.google.com\");\n        command.toObservable()\n                // using BlockingObservable.forEach for demo simplicity\n                .toBlockingObservable().forEach(d -> System.out.println(d));\n        System.out.println(\"Time: \" + command.getExecutionTimeInMilliseconds() \n                + \"  Events: \" + command.getExecutionEvents());\n    }\n\n    public static HystrixObservableCommand<String> bulkheadedNetworkRequest(final String host) {\n        return new HystrixObservableCommand<String>(HystrixCommandGroupKey.Factory.asKey(\"http\")) {\n\n            @Override\n            protected Observable<String> run() {\n                return directNetworkRequest(host);\n            }\n\n            @Override\n            protected Observable<String> getFallback() {\n                return Observable.just(\"Error 500\");\n            }\n\n        };\n    }\n\n    public static Observable<String> directNetworkRequest(String host) {\n        return RxNetty.createHttpClient(host, 80)\n                .submit(HttpClientRequest.createGet(\"/\"))\n                .flatMap(response -> response.getContent())\n                .map(data -> data.toString(Charset.defaultCharset()));\n    }\n```\n\n* [Pull 218](https://github.com/Netflix/Hystrix/pull/218) Hystrix 1.4 - Async/Non-Blocking\n* [Pull 217](https://github.com/Netflix/Hystrix/pull/217) Javanica: Added support for \"Reactive Execution\" and \"Error Propagation\"\n* [Pull 219](https://github.com/Netflix/Hystrix/pull/219) Restore HystrixContext* Constructors without ConcurrencyStrategy\n\n### Version 1.3.16 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.16%22)) ###\n\n* [Pull 258](https://github.com/Netflix/Hystrix/pull/258) Skip CachedObservableOriginal when no getCacheKey()\n* [Pull 259](https://github.com/Netflix/Hystrix/pull/259) Fix #257 with RxJava 0.18.2\n\n\n### Version 1.3.15 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.15%22)) ###\n\n* [Pull 248](https://github.com/Netflix/Hystrix/pull/248) RxJava 0.18 for Hystrix\n* [Pull 249](https://github.com/Netflix/Hystrix/pull/249) Tripped CircuitBreaker Wouldn't Close Under Contention\n* [Pull 229](https://github.com/Netflix/Hystrix/pull/229) Javanica: Added support for Request Cache and Reactive Execution\n* [Pull 242](https://github.com/Netflix/Hystrix/pull/242) Javanica: Cleaner error propagation\n\n\n### Version 1.3.14 (not released) ###\n\n* [Pull 228](https://github.com/Netflix/Hystrix/pull/228) Upgrade 1.3.x to RxJava 0.17.1\n\n\n### Version 1.3.13 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.13%22)) ###\n\n\n* [Pull 216](https://github.com/Netflix/Hystrix/pull/216) hystrix-javanica contrib-module: [annotation support](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica)\n\n\n### Version 1.3.12 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.12%22)) ###\n\n* [Pull 214](https://github.com/Netflix/Hystrix/pull/214) HystrixContextCallable/Runnable Constructors\n\n### Version 1.3.11 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.11%22)) ###\n\n* We'll ignore this release ever happened. Exact same binary as 1.3.10. (It helps to push code to Github before releasing.)\n\n### Version 1.3.10 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.10%22)) ###\n\n* [Pull 211](https://github.com/Netflix/Hystrix/pull/211) Update Javassist version to 3.18.1-GA\n* [Pull 213](https://github.com/Netflix/Hystrix/pull/213) BugFix: Timeout does not propagate request context\n* [Pull 204](https://github.com/Netflix/Hystrix/pull/204) deploying hystrix dashboard on tomcat, SLF4J complains about a missing implementation\n* [Pull 199](https://github.com/Netflix/Hystrix/pull/199) Add new module for publishing metrics to Coda Hale Metrics version 3\n\n### Version 1.3.9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.9%22)) ###\n\n* [Pull 210](https://github.com/Netflix/Hystrix/pull/210) HystrixContextScheduler was not wrapping the Inner Scheduler\n* [Pull 206](https://github.com/Netflix/Hystrix/pull/206) Bugfix ExceptionThreadingUtility\n* [Pull 203](https://github.com/Netflix/Hystrix/pull/203) Made HystrixTimer initialization thread-safe\n\n### Version 1.3.8 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.8%22)) ###\n\n* [Pull 194](https://github.com/Netflix/Hystrix/pull/194) BugFix: Do not overwrite user thread duration in case of timeouts\n\n### Version 1.3.7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.7%22)) ###\n\n* [Pull 189](https://github.com/Netflix/Hystrix/pull/189) BugFix: Race condition between run() and timeout\n* [Pull 190](https://github.com/Netflix/Hystrix/pull/190) BugFix: ConcurrencyStrategy.wrapCallable was not being used on callbacks\n\n\n### Version 1.3.6 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.6%22)) ###\n\n* [Pull 181](https://github.com/Netflix/Hystrix/pull/181) [hystrix-contrib/hystrix-clj] Making Command keys quantified by namespaces\n* [Pull 182](https://github.com/Netflix/Hystrix/pull/182) Removing unused Legend component latent. Removed from html templates/css\n* [Pull 183](https://github.com/Netflix/Hystrix/pull/183) Bugfix to HystrixBadRequestException handling\n* [Pull 184](https://github.com/Netflix/Hystrix/pull/184) BugFix: queue() BadRequestException Handling on Cached Response\n* [Pull 185](https://github.com/Netflix/Hystrix/pull/185) BugFix: Observable.observeOn Scheduler Lost RequestContext\n* [0fb0d3d](https://github.com/Netflix/Hystrix/commit/0fb0d3d25e406f8b6240d312c2ee1f515c77fc13) RxJava 0.14\n\n### Version 1.3.5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.5%22)) ###\n\n* [Pull 179](https://github.com/Netflix/Hystrix/pull/179) RxJava 0.13\n\n### Version 1.3.4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.4%22)) ###\n\n* [f68fa23c](https://github.com/Netflix/Hystrix/commit/bd6dfac5255753978253605f7e8b4c6af68fa23c) RxJava [0.11,0.12)\n\n### Version 1.3.3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.3%22)) ###\n\n* [858e334f](https://github.com/Netflix/Hystrix/commit/7bcf0ee7b876cbfdcb942ea83637d4b5858e334f) RxJava 0.11\n\n### Version 1.3.2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.2%22)) ###\n\n* [Pull 173](https://github.com/Netflix/Hystrix/pull/173) Fix Exception vs Throwable typo in preparation for RxJava 0.11.0\n\n### Version 1.3.1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.1%22)) ###\n\n* [Pull 170](https://github.com/Netflix/Hystrix/pull/170) Add rx support to hystrix-clj\n\n### Version 1.3.0 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.3.0%22)) ###\n\nThis version integrations Hystrix with [RxJava](https://github.com/Netflix/RxJava) to enable non-blocking reactive execution and functional composition.\n\nAsync execution can now be done reactively with the `observe()` method and it will callback when the value is received:\n\n```java\nObservable<String> s = new CommandHelloWorld(\"World\").observe();\n```\n\nA simple example of subscribing to the value (using a Groovy lambda instead of anonymous inner class):\n\n```groovy\ns.subscribe({ value -> println(value) })\n```\n\nA \"Hello World\" example of reactive execution can be [found on the wiki](https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Reactive-Execution).\n\nMore can be learned about RxJava and the composition features at https://github.com/Netflix/RxJava/wiki\n\nThis release is a major refactoring of the Hystrix codebase. To assert correctness and performance it was run in production canary servers on the Netflix API several times during development and for over a week during release candidate stages. Prior to this release the 1.3.0.RC1 version has been running in full Netflix API production for several days performing billions of executions a day.\n\n* [Pull 151](https://github.com/Netflix/Hystrix/pull/151) Version 1.3 - RxJava Observable Integration\n* [Pull 158](https://github.com/Netflix/Hystrix/pull/158) Expose current HystrixCommand to fns\n\n\n### Version 1.2.18 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.18%22)) ###\n\n* [Pull 152](https://github.com/Netflix/Hystrix/pull/152) Escape meta-characters to fix dashboard\n* [Pull 156](https://github.com/Netflix/Hystrix/pull/156) Improve hystrix-clj docs\n* [Pull 155](https://github.com/Netflix/Hystrix/pull/155) Reset Hystrix after hystrix-clj tests have run\n\n### Version 1.2.17 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.17%22)) ###\n\n* [Pull 138](https://github.com/Netflix/Hystrix/pull/138) Eclipse and IDEA Config\n* [Pull 141](https://github.com/Netflix/Hystrix/pull/141) Upgrade Clojuresque (hystrix-clj builds)\n* [Pull 139](https://github.com/Netflix/Hystrix/pull/139) Fix dashboard math bug on thread pool rate calculations\n* [Pull 149](https://github.com/Netflix/Hystrix/pull/149) Allow getFallback to query failure states\n\n### Version 1.2.16 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.16%22)) ###\n\n* [Pull 132](https://github.com/Netflix/Hystrix/pull/132) Add `with-context` macro for conviently wrapping collapsers in thier own context\n* [Pull 136](https://github.com/Netflix/Hystrix/pull/136) Fixed the mock stream\n* [Pull 137](https://github.com/Netflix/Hystrix/pull/137) Limit scope of CurrentThreadExecutingCommand\n\n### Version 1.2.15 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.15%22)) ###\n\nThis is fixing a bug introduced in the last release that affects semaphore isolated commands that use request caching.\n\n* [Pull 133](https://github.com/Netflix/Hystrix/pull/133) Fix NoSuchElement Exception\n\n### Version 1.2.14 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.14%22)) ###\n\n* [Issue 116](https://github.com/Netflix/Hystrix/issues/116) Mechanism for Auditing Network Access Not Isolated by Hystrix\n \nA new module for instrumenting network access to identify calls not wrapped by Hystrix.\n\nSee the module README for more information: https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-network-auditor-agent\n\n### Version 1.2.13 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.13%22)) ###\n\n* [Issue 127](https://github.com/Netflix/Hystrix/issues/127) Add destroy() method to MetricsServlet\n\n### Version 1.2.12 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.12%22)) ###\n\n* [Issue 124](https://github.com/Netflix/Hystrix/issues/124) NPE if Hystrix.reset() called when it's already shutdown\n\n### Version 1.2.11 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.11%22)) ###\n\n* [Issue 113](https://github.com/Netflix/Hystrix/issues/113) IllegalStateException: Future Not Started (on thread pool rejection with response caching)\n* [Issue 118](https://github.com/Netflix/Hystrix/issues/118) Semaphore counter scope was global instead of per-key\n* [Pull 121](https://github.com/Netflix/Hystrix/issues/121) Concurrent execution metric for semaphore and thread isolation\n\n### Version 1.2.10 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.10%22)) ###\n\n* [Issue 80](https://github.com/Netflix/Hystrix/issues/80) HystrixCollapser Concurrency and Performance Fixes\n\n### Version 1.2.9 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.9%22)) ###\n\n* [Issue 109](https://github.com/Netflix/Hystrix/issues/109) Hystrix.reset() now shuts down HystrixTimer\n* [Pull 110](https://github.com/Netflix/Hystrix/issues/110) hystrix-clj cleanup\n* [Pull 112](https://github.com/Netflix/Hystrix/issues/112) Further work on HystrixCollapser IllegalStateException ([Issue 80](https://github.com/Netflix/Hystrix/issues/80))\n\n### Version 1.2.8 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.8%22)) ###\n\n* [Issue 102](https://github.com/Netflix/Hystrix/issues/102) Hystrix.reset() functionality for clean shutdown and resource cleanup\n* [Pull 103](https://github.com/Netflix/Hystrix/issues/103) hystrix-clj cleanup\n* [Pull 104](https://github.com/Netflix/Hystrix/issues/104) javadoc clarification\n* [Pull 105](https://github.com/Netflix/Hystrix/issues/104) Added IntelliJ IDEA support, cleanup to Eclipse support\n\n### Version 1.2.7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.7%22)) ###\n\n* [Pull 99](https://github.com/Netflix/Hystrix/issues/99) Experimental Clojure Bindings [hystrix-clj](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-clj)\n\n### Version 1.2.6 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.6%22)) ###\n\n* [Issue 96](https://github.com/Netflix/Hystrix/issues/96) Remove 'final' modifiers to allow mocking\n\n### Version 1.2.5 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.5%22)) ###\n\n* [Pull 94](https://github.com/Netflix/Hystrix/pull/94) Force character encoding for event stream to utf-8\n* [Issue 60](https://github.com/Netflix/Hystrix/issues/60) Dashboard: Hover for full name (when shortened with ellipsis)\n* [Issue 53](https://github.com/Netflix/Hystrix/issues/53) RequestLog: Reduce Chance of Memory Leak\n \n### Version 1.2.4 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.4%22)) ###\n\n* [Pull 91](https://github.com/Netflix/Hystrix/pull/91) handle null circuit breaker in HystrixMetricsPoller\n\n### Version 1.2.3 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.3%22)) ###\n\n* [Issue 85](https://github.com/Netflix/Hystrix/issues/85) hystrix.stream holds connection open if no metrics\n* [Pull 84](https://github.com/Netflix/Hystrix/pull/84) include 'provided' dependencies in Eclipse project classpath\n\n### Version 1.2.2 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.2%22)) ###\n\n* [Issue 82](https://github.com/Netflix/Hystrix/issues/82) ThreadPool stream should include reportingHosts\n\n### Version 1.2.1 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.1%22)) ###\n\n* [Issue 80](https://github.com/Netflix/Hystrix/issues/80) IllegalStateException: Future Not Started\n* [Issue 78](https://github.com/Netflix/Hystrix/issues/78) Include more info when collapsed requests remain in queue\n\n### Version 1.2.0 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.2.0%22)) ###\n\n* [Issue 10](https://github.com/Netflix/Hystrix/issues/10) HystrixCommand Execution Hooks via Plugin\n  * [Pull 71](https://github.com/Netflix/Hystrix/pull/71) Change Throwable to Exception \n  * [Pull 71](https://github.com/Netflix/Hystrix/pull/71) jettyRun support for running webapps via gradle\n* [Issue 15](https://github.com/Netflix/Hystrix/issues/15) Property to disable percentile calculations\n* [Issue 69](https://github.com/Netflix/Hystrix/issues/69) Property to disable fallbacks\n* [Pull 73](https://github.com/Netflix/Hystrix/pull/73) Make servlet-api a provided dependency\n* [Pull 74](https://github.com/Netflix/Hystrix/pull/74) Dashboard problem when using Turbine (Stream not flushing)\n\n### Version 1.1.7 ([Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20v%3A%221.1.7%22)) ###\n\n* [Pull 67](https://github.com/Netflix/Hystrix/pull/67) Unit tests for request log and checked exceptions\n* [Pull 66](https://github.com/Netflix/Hystrix/pull/66) Making provided scope transtive\n* [Pull 65](https://github.com/Netflix/Hystrix/pull/65) Fixed gitignore definition of build output directories\n* [Issue 63](https://github.com/Netflix/Hystrix/issues/63) Add \"throws Exception\" to HystrixCommand run() method\n* [Pull 62](https://github.com/Netflix/Hystrix/pull/62) applying js fixes to threadPool ui\n* [Pull 61](https://github.com/Netflix/Hystrix/pull/61) Request log with timeouts\n* [Issue 55](https://github.com/Netflix/Hystrix/issues/55) HysrixRequestLog: Missing Events and Time on Timeouts\n* [Issue 20](https://github.com/Netflix/Hystrix/issues/20) TotalExecutionTime not tracked on queue()\n* [Pull 57](https://github.com/Netflix/Hystrix/pull/57) Dashboard js fix\n* [Issue 39](https://github.com/Netflix/Hystrix/issues/39) HystrixPlugins Bootstrapping Problem - Race Conditions\n* [Pull 52](https://github.com/Netflix/Hystrix/pull/52) Gradle Build Changes\n\n### Version 1.1.6 ###\n\n* [Pull 51](https://github.com/Netflix/Hystrix/pull/51) Merging in gradle-template, specifically provided\n\n### Version 1.1.5 ###\n\n* [Pull 50](https://github.com/Netflix/Hystrix/pull/50) Make javax.servlet-api a 'provided' dependency not 'compile'\n\n### Version 1.1.4 ###\n\n* [Pull 49](https://github.com/Netflix/Hystrix/pull/49) Cleaner design (for metrics) by injecting listener into constructor.\n\n### Version 1.1.3 ###\n\n* [Pull 47](https://github.com/Netflix/Hystrix/pull/47) Support pausing/resuming metrics poller\n* [Pull 48](https://github.com/Netflix/Hystrix/pull/48) Fixing non-deterministic unit test\n* README files added to submodules\n\n### Version 1.1.2 ###\n\n* [Pull 44](https://github.com/Netflix/Hystrix/pull/44) Hystrix Dashboard\n\n### Version 1.1.1 ###\n\n* [Issue 24](https://github.com/Netflix/Hystrix/issues/24) Yammer Metrics Support\n* [Pull 43](https://github.com/Netflix/Hystrix/pull/43) Fix the wrong percentile for latencyExecute_percentile_75 in the Servo publisher\n\n### Version 1.1.0 ###\n\n* [Pull 32](https://github.com/Netflix/Hystrix/pull/32) servo-event-stream module\n* [Pull 33](https://github.com/Netflix/Hystrix/pull/33) Remove Servo dependency from core, move to submodule\n* [Pull 35](https://github.com/Netflix/Hystrix/pull/35) Metrics event stream\n* [Issue 34](https://github.com/Netflix/Hystrix/issues/34) Remove Strategy Injection on HystrixCommand\n* [Pull 36](https://github.com/Netflix/Hystrix/pull/36) example webapp\n* [Pull 37](https://github.com/Netflix/Hystrix/pull/37) Migrate metrics stream from org.json.JSONObject to Jackson\n\n### Version 1.0.3 ###\n\n* [Pull 4](https://github.com/Netflix/Hystrix/pull/4) Contrib request context servlet filters \n* [Pull 16](https://github.com/Netflix/Hystrix/pull/16) Change logger from info to debug for property changes\n* [Issue 12](https://github.com/Netflix/Hystrix/issues/12) Use logger.error not logger.debug for fallback failure\n* [Issue 8](https://github.com/Netflix/Hystrix/issues/8) Capture exception from run() and expose getter\n* [Issue 22](https://github.com/Netflix/Hystrix/issues/22) Default Collapser scope to REQUEST if using Setter\n* [Pull 27](https://github.com/Netflix/Hystrix/pull/27) Initialize HealthCounts to non-null value\n* [Issue 28](https://github.com/Netflix/Hystrix/issues/28) Thread pools lost custom names in opensource refactoring\n* [Pull 30](https://github.com/Netflix/Hystrix/pull/30) Simplified access to HystrixCommandMetrics\n* Javadoc and README changes\n\n### Version 1.0.2 ###\n\n* Javadoc changes\n\n### Version 1.0.0 ###\n\n* Initial open source release \n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Hystrix\n\nIf you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request.\n\nWhen submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible.\n\n## License\n\nBy contributing your code, you agree to license your contribution under the terms of the APLv2: https://github.com/Netflix/Hystrix/blob/master/LICENSE-2.0.txt\n\nAll files are released with the Apache 2.0 license.\n\nIf you are adding a new file it should have a header like this:\n\n```\n/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n ```\n"
  },
  {
    "path": "LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2012 Netflix, Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "OSSMETADATA",
    "content": "osslifecycle=maintenance\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://netflix.github.io/Hystrix/images/hystrix-logo-tagline-850.png\">\n\n# Hystrix: Latency and Fault Tolerance for Distributed Systems\n\n[![NetflixOSS Lifecycle](https://img.shields.io/osslifecycle/Netflix/hystrix.svg)]()\n[![][travis img]][travis]\n[![][maven img]][maven]\n[![][license img]][license]\n\n# Hystrix Status\nHystrix is no longer in active development, and is currently in maintenance mode.\n\nHystrix (at version 1.5.18) is stable enough to meet the needs of Netflix for our existing applications. Meanwhile, our focus has shifted towards more adaptive implementations that react to an application’s real time performance rather than pre-configured settings (for example, through [adaptive concurrency limits](https://medium.com/@NetflixTechBlog/performance-under-load-3e6fa9a60581)). For the cases where something like Hystrix makes sense, we intend to continue using Hystrix for existing applications, and to leverage open and active projects like [resilience4j](https://github.com/resilience4j/resilience4j) for new internal projects. We are beginning to recommend others do the same.\n\nNetflix Hystrix is now officially in maintenance mode, with the following expectations to the greater community: \nNetflix will no longer actively review issues, merge pull-requests, and release new versions of Hystrix. \nWe have made a final release of Hystrix (1.5.18) per [issue 1891](https://github.com/Netflix/Hystrix/issues/1891) so that the latest version in Maven Central is aligned with the last known stable version used internally at Netflix (1.5.11). \nIf members of the community are interested in taking ownership of Hystrix and moving it back into active mode, please reach out to hystrixoss@googlegroups.com.\n\nHystrix has served Netflix and the community well over the years, and the transition to maintenance mode is in no way an indication that the concepts and ideas from Hystrix are no longer valuable. On the contrary, Hystrix has inspired many great ideas and projects. We thank everyone at Netflix, and in the greater community, for all the contributions made to Hystrix over the years.\n\n## Introduction\n\nHystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.\n\n## Full Documentation\n\nSee the [Wiki](https://github.com/Netflix/Hystrix/wiki/) for full documentation, examples, operational details and other information.\n\nSee the [Javadoc](http://netflix.github.com/Hystrix/javadoc) for the API.\n\n## Communication\n\n- Google Group: [HystrixOSS](http://groups.google.com/d/forum/hystrixoss)\n- Twitter: [@HystrixOSS](http://twitter.com/HystrixOSS)\n- [GitHub Issues](https://github.com/Netflix/Hystrix/issues)\n\n## What does it do?\n\n#### 1) Latency and Fault Tolerance\n\nStop cascading failures. Fallbacks and graceful degradation. Fail fast and rapid recovery. \n\nThread and semaphore isolation with circuit breakers. \n\n#### 2) Realtime Operations\n\nRealtime monitoring and configuration changes. Watch service and property changes take effect immediately as they spread across a fleet. \n\nBe alerted, make decisions, affect change and see results in seconds. \n\n#### 3) Concurrency\n\nParallel execution. Concurrency aware request caching. Automated batching through request collapsing.\n\n## Hello World!\n\nCode to be isolated is wrapped inside the run() method of a HystrixCommand similar to the following:\n\n```java\npublic class CommandHelloWorld extends HystrixCommand<String> {\n\n    private final String name;\n\n    public CommandHelloWorld(String name) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.name = name;\n    }\n\n    @Override\n    protected String run() {\n        return \"Hello \" + name + \"!\";\n    }\n}\n```\n\nThis command could be used like this:\n\n```java\nString s = new CommandHelloWorld(\"Bob\").execute();\nFuture<String> s = new CommandHelloWorld(\"Bob\").queue();\nObservable<String> s = new CommandHelloWorld(\"Bob\").observe();\n```\n\nMore examples and information can be found in the [How To Use](https://github.com/Netflix/Hystrix/wiki/How-To-Use) section.\n\nExample source code can be found in the [hystrix-examples](https://github.com/Netflix/Hystrix/tree/master/hystrix-examples/src/main/java/com/netflix/hystrix/examples) module.\n\n## Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20a%3A%22hystrix-core%22).\n\nChange history and version numbers => [CHANGELOG.md](https://github.com/Netflix/Hystrix/blob/master/CHANGELOG.md)\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-core</artifactId>\n    <version>x.y.z</version>\n</dependency>\n```\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-core\" rev=\"x.y.z\" />\n```\n\nIf you need to download the jars instead of using a build system, create a Maven pom file like this with the desired version:\n\n```xml\n<?xml version=\"1.0\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>com.netflix.hystrix.download</groupId>\n\t<artifactId>hystrix-download</artifactId>\n\t<version>1.0-SNAPSHOT</version>\n\t<name>Simple POM to download hystrix-core and dependencies</name>\n\t<url>http://github.com/Netflix/Hystrix</url>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.netflix.hystrix</groupId>\n\t\t\t<artifactId>hystrix-core</artifactId>\n\t\t\t<version>x.y.z</version>\n\t\t\t<scope/>\n\t\t</dependency>\n\t</dependencies>\n</project>\n```\n\nThen execute:\n\n```\nmvn -f download-hystrix-pom.xml dependency:copy-dependencies\n```\n\nIt will download hystrix-core-*.jar and its dependencies into ./target/dependency/.\n\nYou need Java 6 or later.\n\n## Build\n\nTo build:\n\n```\n$ git clone git@github.com:Netflix/Hystrix.git\n$ cd Hystrix/\n$ ./gradlew build\n```\n\nFurther details on building can be found on the [Getting Started](https://github.com/Netflix/Hystrix/wiki/Getting-Started) page of the wiki.\n\n## Run Demo\n\nTo run a [demo app](https://github.com/Netflix/Hystrix/tree/master/hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/HystrixCommandDemo.java) do the following:\n\n```\n$ git clone git@github.com:Netflix/Hystrix.git\n$ cd Hystrix/\n./gradlew runDemo\n```\n\nYou will see output similar to the following:\n\n```\nRequest => GetUserAccountCommand[SUCCESS][8ms], GetPaymentInformationCommand[SUCCESS][20ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][101ms], CreditCardCommand[SUCCESS][1075ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][2ms], GetPaymentInformationCommand[SUCCESS][22ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][130ms], CreditCardCommand[SUCCESS][1050ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][4ms], GetPaymentInformationCommand[SUCCESS][19ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][145ms], CreditCardCommand[SUCCESS][1301ms]\nRequest => GetUserAccountCommand[SUCCESS][4ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][93ms], CreditCardCommand[SUCCESS][1409ms]\n\n#####################################################################################\n# CreditCardCommand: Requests: 17 Errors: 0 (0%)   Mean: 1171 75th: 1391 90th: 1470 99th: 1486 \n# GetOrderCommand: Requests: 21 Errors: 0 (0%)   Mean: 100 75th: 144 90th: 207 99th: 230 \n# GetUserAccountCommand: Requests: 21 Errors: 4 (19%)   Mean: 8 75th: 11 90th: 46 99th: 51 \n# GetPaymentInformationCommand: Requests: 21 Errors: 0 (0%)   Mean: 18 75th: 21 90th: 24 99th: 25 \n#####################################################################################\n\nRequest => GetUserAccountCommand[SUCCESS][10ms], GetPaymentInformationCommand[SUCCESS][16ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][51ms], CreditCardCommand[SUCCESS][922ms]\nRequest => GetUserAccountCommand[SUCCESS][12ms], GetPaymentInformationCommand[SUCCESS][12ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][68ms], CreditCardCommand[SUCCESS][1257ms]\nRequest => GetUserAccountCommand[SUCCESS][10ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][78ms], CreditCardCommand[SUCCESS][1295ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][6ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][153ms], CreditCardCommand[SUCCESS][1321ms]\n```\n\nThis demo simulates 4 different [HystrixCommand](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java) implementations with failures, latency, timeouts and duplicate calls in a multi-threaded environment.\n\nIt logs the results of [HystrixRequestLog](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java) and metrics from [HystrixCommandMetrics](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandMetrics.java).\n\n## Dashboard\n\nThe hystrix-dashboard component of this project has been deprecated and moved to [Netflix-Skunkworks/hystrix-dashboard](https://github.com/Netflix-Skunkworks/hystrix-dashboard). Please see the README there for more details including important security considerations.\n\n\n## Bugs and Feedback\n\nFor bugs, questions and discussions please use the [GitHub Issues](https://github.com/Netflix/Hystrix/issues).\n\n \n## LICENSE\n\nCopyright 2013 Netflix, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n<http://www.apache.org/licenses/LICENSE-2.0>\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n[travis]:https://travis-ci.org/Netflix/Hystrix\n[travis img]:https://travis-ci.org/Netflix/Hystrix.svg?branch=master\n\n[maven]:http://search.maven.org/#search|gav|1|g:\"com.netflix.hystrix\"%20AND%20a:\"hystrix-core\"\n[maven img]:https://maven-badges.herokuapp.com/maven-central/com.netflix.hystrix/hystrix-core/badge.svg\n\n[release]:https://github.com/netflix/hystrix/releases\n[release img]:https://img.shields.io/github/release/netflix/hystrix.svg\n\n[license]:LICENSE-2.0.txt\n[license img]:https://img.shields.io/badge/License-Apache%202-blue.svg\n\n"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n    id \"com.netflix.nebula.netflixoss\" version \"11.3.1\"\n    id \"me.champeau.jmh\" version \"0.7.1\"\n}\n\nallprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n\nsubprojects {\n    apply plugin: 'nebula.netflixoss'\n    apply plugin: 'java-library'\n\n    group = \"com.netflix.hystrix\"\n\n    tasks.withType(Javadoc).configureEach {\n        failOnError = false\n    }\n}\n"
  },
  {
    "path": "codequality/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n    \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\"\n    \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">\n\n<module name=\"Checker\">\n\n    <!-- Checks that a package-info.java file exists for each package.     -->\n    <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->\n    <!--\n    <module name=\"JavadocPackage\">\n      <property name=\"allowLegacy\" value=\"true\"/>\n    </module>\n    -->\n\n    <!-- Checks whether files end with a new line.                        -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->\n    <module name=\"NewlineAtEndOfFile\"/>\n\n    <!-- Checks that property files contain the same keys.         -->\n    <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->\n    <module name=\"Translation\"/>\n\n    <!-- Checks for Size Violations.                    -->\n    <!-- See http://checkstyle.sf.net/config_sizes.html -->\n    <module name=\"FileLength\"/>\n\n    <!-- Checks for whitespace                               -->\n    <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n    <module name=\"FileTabCharacter\"/>\n\n    <!-- Miscellaneous other checks.                   -->\n    <!-- See http://checkstyle.sf.net/config_misc.html -->\n    <module name=\"RegexpSingleline\">\n       <property name=\"format\" value=\"\\s+$\"/>\n       <property name=\"minimum\" value=\"0\"/>\n       <property name=\"maximum\" value=\"0\"/>\n       <property name=\"message\" value=\"Line has trailing spaces.\"/>\n       <property name=\"severity\" value=\"info\"/>\n    </module>\n\n    <module name=\"TreeWalker\">\n\n        <!-- Checks for Javadoc comments.                     -->\n        <!-- See http://checkstyle.sf.net/config_javadoc.html -->\n        <module name=\"JavadocMethod\">\n          <property name=\"scope\" value=\"package\"/>\n          <property name=\"allowMissingParamTags\" value=\"true\"/>\n          <property name=\"allowMissingThrowsTags\" value=\"true\"/>\n          <property name=\"allowMissingReturnTag\" value=\"true\"/>\n          <property name=\"allowThrowsTagsForSubclasses\" value=\"true\"/>\n          <property name=\"allowUndeclaredRTE\" value=\"true\"/>\n          <property name=\"allowMissingPropertyJavadoc\" value=\"true\"/>\n        </module>\n        <module name=\"JavadocType\">\n          <property name=\"scope\" value=\"package\"/>\n        </module>\n        <module name=\"JavadocVariable\">\n          <property name=\"scope\" value=\"package\"/>\n        </module>\n        <module name=\"JavadocStyle\">\n          <property name=\"checkEmptyJavadoc\" value=\"true\"/>\n        </module>\n\n        <!-- Checks for Naming Conventions.                  -->\n        <!-- See http://checkstyle.sf.net/config_naming.html -->\n        <module name=\"ConstantName\"/>\n        <module name=\"LocalFinalVariableName\"/>\n        <module name=\"LocalVariableName\"/>\n        <module name=\"MemberName\"/>\n        <module name=\"MethodName\"/>\n        <module name=\"PackageName\"/>\n        <module name=\"ParameterName\"/>\n        <module name=\"StaticVariableName\"/>\n        <module name=\"TypeName\"/>\n\n        <!-- Checks for imports                              -->\n        <!-- See http://checkstyle.sf.net/config_import.html -->\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"IllegalImport\"/> <!-- defaults to sun.* packages -->\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\"/>\n\n\n        <!-- Checks for Size Violations.                    -->\n        <!-- See http://checkstyle.sf.net/config_sizes.html -->\n        <module name=\"LineLength\">\n          <!-- what is a good max value? -->\n          <property name=\"max\" value=\"120\"/>\n          <!-- ignore lines like \"$File: //depot/... $\" -->\n          <property name=\"ignorePattern\" value=\"\\$File.*\\$\"/>\n          <property name=\"severity\" value=\"info\"/>\n        </module>\n        <module name=\"MethodLength\"/>\n        <module name=\"ParameterNumber\"/>\n\n\n        <!-- Checks for whitespace                               -->\n        <!-- See http://checkstyle.sf.net/config_whitespace.html -->\n        <module name=\"EmptyForIteratorPad\"/>\n        <module name=\"GenericWhitespace\"/>\n        <module name=\"MethodParamPad\"/>\n        <module name=\"NoWhitespaceAfter\"/>\n        <module name=\"NoWhitespaceBefore\"/>\n        <module name=\"OperatorWrap\"/>\n        <module name=\"ParenPad\"/>\n        <module name=\"TypecastParenPad\"/>\n        <module name=\"WhitespaceAfter\"/>\n        <module name=\"WhitespaceAround\"/>\n\n        <!-- Modifier Checks                                    -->\n        <!-- See http://checkstyle.sf.net/config_modifiers.html -->\n        <module name=\"ModifierOrder\"/>\n        <module name=\"RedundantModifier\"/>\n\n\n        <!-- Checks for blocks. You know, those {}'s         -->\n        <!-- See http://checkstyle.sf.net/config_blocks.html -->\n        <module name=\"AvoidNestedBlocks\"/>\n        <module name=\"EmptyBlock\">\n          <property name=\"option\" value=\"text\"/>\n        </module>\n        <module name=\"LeftCurly\"/>\n        <module name=\"NeedBraces\"/>\n        <module name=\"RightCurly\"/>\n\n\n        <!-- Checks for common coding problems               -->\n        <!-- See http://checkstyle.sf.net/config_coding.html -->\n        <!-- <module name=\"AvoidInlineConditionals\"/> -->\n        <module name=\"EmptyStatement\"/>\n        <module name=\"EqualsHashCode\"/>\n        <module name=\"HiddenField\">\n          <property name=\"ignoreConstructorParameter\" value=\"true\"/>\n          <property name=\"ignoreSetter\" value=\"true\"/>\n          <property name=\"severity\" value=\"warning\"/>\n        </module>\n        <module name=\"IllegalInstantiation\"/>\n        <module name=\"InnerAssignment\"/>\n        <module name=\"MagicNumber\">\n          <property name=\"severity\" value=\"warning\"/>\n        </module>\n        <module name=\"MissingSwitchDefault\"/>\n        <!-- Problem with finding exception types... -->\n        <module name=\"RedundantThrows\">\n          <property name=\"allowUnchecked\" value=\"true\"/>\n          <property name=\"suppressLoadErrors\" value=\"true\"/>\n          <property name=\"severity\" value=\"info\"/>\n        </module>\n        <module name=\"SimplifyBooleanExpression\"/>\n        <module name=\"SimplifyBooleanReturn\"/>\n\n        <!-- Checks for class design                         -->\n        <!-- See http://checkstyle.sf.net/config_design.html -->\n        <!-- <module name=\"DesignForExtension\"/> -->\n        <module name=\"FinalClass\"/>\n        <module name=\"HideUtilityClassConstructor\"/>\n        <module name=\"InterfaceIsType\"/>\n        <module name=\"VisibilityModifier\"/>\n\n\n        <!-- Miscellaneous other checks.                   -->\n        <!-- See http://checkstyle.sf.net/config_misc.html -->\n        <module name=\"ArrayTypeStyle\"/>\n        <!-- <module name=\"FinalParameters\"/> -->\n        <module name=\"TodoComment\">\n          <property name=\"format\" value=\"TODO\"/>\n          <property name=\"severity\" value=\"info\"/>\n        </module>\n        <module name=\"UpperEll\"/>\n\n        <module name=\"FileContentsHolder\"/> <!-- Required by comment suppression filters -->\n\n    </module>\n\n    <!-- Enable suppression comments -->\n    <module name=\"SuppressionCommentFilter\">\n      <property name=\"offCommentFormat\" value=\"CHECKSTYLE IGNORE\\s+(\\S+)\"/>\n      <property name=\"onCommentFormat\" value=\"CHECKSTYLE END IGNORE\\s+(\\S+)\"/>\n      <property name=\"checkFormat\" value=\"$1\"/>\n    </module>\n    <module name=\"SuppressWithNearbyCommentFilter\">\n      <!-- Syntax is \"SUPPRESS CHECKSTYLE name\" -->\n      <property name=\"commentFormat\" value=\"SUPPRESS CHECKSTYLE (\\w+)\"/>\n      <property name=\"checkFormat\" value=\"$1\"/>\n      <property name=\"influenceFormat\" value=\"1\"/>\n    </module>\n</module>\n"
  },
  {
    "path": "gradle/javadocStyleSheet.css",
    "content": "# originally from http://sensemaya.org/files/stylesheet.css and then modified\n# http://sensemaya.org/maya/2009/07/10/making-javadoc-more-legible\n\n/* Javadoc style sheet */\n\n/* Define colors, fonts and other style attributes here to override the defaults */\n\n/* Page background color */\nbody { background-color: #FFFFFF; color:#333; font-size: 100%; }\n\nbody { font-size: 0.875em; line-height: 1.286em; font-family:   \"Helvetica\", \"Arial\", sans-serif; }\n\ncode { color: #777; line-height: 1.286em; font-family: \"Consolas\", \"Lucida Console\", \"Droid Sans Mono\", \"Andale Mono\", \"Monaco\", \"Lucida Sans Typewriter\"; }\n\na { text-decoration: none; color: #16569A; /* also try #2E85ED, #0033FF, #6C93C6, #1D7BBE, #1D8DD2 */ }\na:hover { text-decoration: underline; }\n\n\ntable[border=\"1\"] { border: 1px solid #ddd; }\ntable[border=\"1\"] td, table[border=\"1\"] th { border: 1px solid #ddd; }\ntable[cellpadding=\"3\"] td { padding: 0.5em; }\n\nfont[size=\"-1\"] { font-size: 0.85em; line-height: 1.5em; }\nfont[size=\"-2\"] { font-size: 0.8em; }\nfont[size=\"+2\"] { font-size: 1.4em; line-height: 1.3em; padding: 0.4em 0; }\n\n/* Headings */\nh1 { font-size: 1.5em; line-height: 1.286em;}\nh2.title { color: #c81f08; }\n\n/* Table colors */\n.TableHeadingColor     { background: #ccc; color:#444; } /* Dark mauve */\n.TableSubHeadingColor  { background: #ddd; color:#444; } /* Light mauve */\n.TableRowColor         { background: #FFFFFF; color:#666; font-size: 0.95em; } /* White */\n.TableRowColor code    { color:#000; } /* White */\n\n/* Font used in left-hand frame lists */\n.FrameTitleFont   { font-size: 100%; }\n.FrameHeadingFont { font-size:  90%; }\n.FrameItemFont { font-size:  0.9em; line-height: 1.3em; \n}\n/* Java Interfaces */\n.FrameItemFont a i {\n  font-style: normal; color: #16569A;\n}\n.FrameItemFont a:hover i {\n  text-decoration: underline;\n}\n\n\n/* Navigation bar fonts and colors */\n.NavBarCell1    { background-color:#E0E6DF; } /* Light mauve */\n.NavBarCell1Rev { background-color:#16569A; color:#FFFFFF} /* Dark Blue */\n.NavBarFont1    { }\n.NavBarFont1Rev { color:#FFFFFF; }\n\n.NavBarCell2    { background-color:#FFFFFF; color:#000000}\n.NavBarCell3    { background-color:#FFFFFF; color:#000000}\n\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jun 19 21:27:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.1.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": ""
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "hystrix-contrib/README.md",
    "content": "## hystrix-contrib\n\nThis is the parent of all \"contrib\" submodules to Hystrix. \n\nExamples of what makes sense as a contrib submodule are:\n\n- alternate implementations of [HystrixMetricsPublisher](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisher.html)\n- alternate implementations of [HystrixPropertiesStrategy](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.html)\n- request lifecycle implementations (such as [hystrix-request-servlet](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet))\n- implementations of [HystrixEventNotifier](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/strategy/eventnotifier/HystrixEventNotifier.html)\n- dashboard and monitoring tools\n\n3rd partly libraries wrapped with Hystrix do not belong here and should be their own project.\n\nThey can however be referenced from the Wiki [Libraries](https://github.com/Netflix/Hystrix/wiki/Libraries) page.\n"
  },
  {
    "path": "hystrix-contrib/hystrix-clj/README.md",
    "content": "# Hystrix Clojure Bindings\n\nThis module contains idiomatic Clojure bindings for Hystrix.\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-clj%22).\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-clj</artifactId>\n    <version>x.y.z</version>\n</dependency>\n```\n\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-clj\" rev=\"x.y.z\" />\n```\n\nand for Leiningen:\n\n```clojure\n[com.netflix.hystrix/hystrix-clj \"x.y.z\"]\n```\n\n# Usage\n\nPlease see the docstrings in src/com/netflix/hystrix/core.clj for extensive usage info.\n\n## TL;DR\nYou have a function that interacts with an untrusted dependency:\n\n```clojure\n(defn make-request\n  [arg]\n  ... make the request ...)\n\n; execute the request\n(make-request \"baz\")\n```\n\nand you want to make it a Hystrix dependency command. Do this:\n\n```clojure\n(defcommand make-request\n  [arg]\n  ... make the request ...)\n\n; execute the request\n(make-request \"baz\")\n\n; or queue for async execution\n(queue #'make-request \"baz\")\n```\n\n# Event Stream\n\nA Clojure version of hystrix-event-stream can be found at https://github.com/josephwilk/hystrix-event-stream-clj\n"
  },
  {
    "path": "hystrix-contrib/hystrix-clj/build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n        maven{\n          name 'clojars'\n          url 'https://clojars.org/repo'\n        }\n    }\n    dependencies {\n        classpath 'com.netflix.nebula:nebula-clojure-plugin:13.0.1'\n    }\n}\napply plugin: 'com.netflix.nebula.clojure' // this is a wrapper around clojuresque to make it behave well with other plugins\n\nrepositories {\n    mavenCentral()\n    clojarsRepo()\n}\n\ndependencies {\n    api project(':hystrix-core')\n    implementation 'org.clojure:clojure:1.7.0'\n}\n\n/*\n * Add Counterclockwise and include 'provided' dependencies\n */\neclipse {\n  project {\n    natures \"ccw.nature\"\n  }\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Define a task that runs an nrepl server. The port is given with the nreplPort\n// property:\n//    gradlew nrepl -PnreplPort=9999\n// or put the property in ~/.gradle/gradle.properties\ndef nreplPort = 9999 // hardcoding to 9999 until figuring out how to make this not break Eclipse project import when the property isn't defined\nconfigurations { nrepl }\ndependencies { nrepl 'org.clojure:tools.nrepl:0.2.1' }\ntask nrepl(type: JavaExec) {\n    classpath configurations.nrepl.asPath,\n              project.sourceSets.main.clojure.srcDirs,\n              project.sourceSets.test.clojure.srcDirs,\n              sourceSets.main.runtimeClasspath\n    main = \"clojure.main\"\n    args '--eval', \"(ns gradle-nrepl (:require [clojure.tools.nrepl.server :refer (start-server stop-server)]))\",\n        '--eval', \"(println \\\"Starting nrepl server on port $nreplPort\\\")\",\n        '--eval', \"(def server (start-server :port $nreplPort))\"\n}\n\n// vim:ft=groovy\n"
  },
  {
    "path": "hystrix-contrib/hystrix-clj/src/main/clojure/com/netflix/hystrix/core.clj",
    "content": ";;\n;; Copyright 2015 Netflix, Inc.\n;;\n;; Licensed under the Apache License, Version 2.0 (the \"License\");\n;; you may not use this file except in compliance with the License.\n;; You may obtain a copy of the License at\n;;\n;; http://www.apache.org/licenses/LICENSE-2.0\n;;\n;; Unless required by applicable law or agreed to in writing, software\n;; distributed under the License is distributed on an \"AS IS\" BASIS,\n;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n;; See the License for the specific language governing permissions and\n;; limitations under the License.\n\n(ns com.netflix.hystrix.core\n  \"THESE BINDINGS ARE EXPERIMENTAL AND SUBJECT TO CHANGE\n\n  Functions for defining and executing Hystrix dependency commands and collapsers.\n\n  The definition of commands and collapers is separated from their instantiation and execution.\n  They are represented as plain Clojure maps (see below) which are later instantiated into\n  functional HystrixCommand or HystrixCollapser instances. defcommand and defcollapser macros\n  are provided to assist in defining these maps.\n\n  A command or collapser definition map can be passed to the execute and queue functions to\n  invoke the command.\n\n  The main Hystrix documentation can be found at https://github.com/Netflix/Hystrix. In particular,\n  you may find the Javadocs useful if you need to drop down into Java:\n  http://netflix.github.io/Hystrix/javadoc/\n\n  # HystrixCommand\n\n  A HystrixCommand is a representation for an interaction with a network dependency, or other\n  untrusted resource. See the Hystrix documentation (https://github.com/Netflix/Hystrix) for\n  more details.\n\n  A command is defined by a map with the following keys:\n\n    :type\n\n      Always :command. Required.\n\n    :group-key\n\n      A HystrixCommandGroupKey, string, or keyword. Required.\n\n    :command-key\n\n      A HystrixCommandKey, string, or keyword. Required.\n\n    :thread-pool-key\n\n      A HystrixThreadPoolKey, string, or keyword. Optional, defaults to :group-key.\n\n    :run-fn\n\n      The function to run for the command. The function may have any number of\n      arguments. Required.\n\n    :fallback-fn\n\n      A function with the same args as :run-fn that calculates a fallback result when\n      the command fails. Optional, defaults to a function that throws UnsupportedOperationException.\n\n    :cache-key-fn\n\n      A function which the same args as :run-fn that calculates a cache key for the\n      given args. Optional, defaults to nil, i.e. no caching.\n\n    :init-fn\n\n      A function that takes a definition map and HystrixCommand$Setter which should return\n      a HystrixCommand$Setter (usually the one passed in) to ultimately be passed to the\n      constructor of the HystrixCommand. For example,\n\n          (fn [_ setter]\n            (.andCommandPropertiesDefaults setter ...))\n\n      This is your escape hatch into raw Hystrix.\n      ... but NOTE: Hystrix does a fair bit of configuration caching and that caching is keyed\n      by command key. Thus, many of the settings you apply within :init-fn will only apply\n      the *first time it is invoked*. After that, they're ignored. This means that some REPL-based\n      dynamicism is lost and that :init-fn shouldn't be used to configure a HystrixCommand at\n      run-time. Instead use Archaius properties as described in the Hystrix docs.\n\n  The com.netflix.hystrix.core/defcommand macro is a helper for defining this map and storing it\n  in a var. For example, here's a definition for an addition command:\n\n    ; Define a command with :group-key set to the current namespace, *ns*, and with :command-key\n    ; set to \\\"plus\\\". The function the command executes is clojure.core/+.\n    (defcommand plus\n      \\\"My resilient addition operation\\\"\n      [& args]\n      (apply + args))\n    ;=> #'user/plus\n\n    ; Execute the command\n    (plus 1 2 3 4 5)\n    ;=> 15\n\n    ; Queue the command for async operation\n    (def f (queue #'plus 4 5))\n    ;=> java.util.concurrent.Future/clojure.lang.IDeref\n\n    ; Now you can deref the future as usual\n    @f   ; or (.get f)\n    ;=> 9\n\n  # HystrixCollapser\n\n  A HystrixCollapser allows multiple HystrixCommand requests to be batched together if the underlying\n  resource provides such a capability. See the Hystrix documentation (https://github.com/Netflix/Hystrix)\n  for more details.\n\n  A collapser is defined by a map with the following keys:\n\n    :type\n\n      Always :collapser. Required.\n\n    :collapser-key\n\n      A HystrixCollapserKey, string, or keyword. Required.\n\n    :collapse-fn\n\n      A fn that takes a sequence of arg lists and instantiates a new command to\n      execute them. Required. See com.netflix.hystrix.core/instantiate.  This\n      function should be completely free of side effects.\n\n    :map-fn\n\n      A fn that takes sequence of arg lists (as passed to :collapse-fn) and the\n      result from the command created by :collapse-fn. Must return a sequence of\n      results where the nth element is the result or exception associated with the\n      nth arg list. The arg lists are in the same order as passed to :collapse-fn.\n      Required.  This function should be completely free of side effects.\n\n    :scope\n\n      The collapser scope, :request or :global. Optional, defaults to :request.\n\n    :shard-fn\n\n      A fn that takes a sequence of arg lists and shards them, returns a sequence of\n      sequence of arg lists. Optional, defaults to no sharding.  This function should\n      be completely free of side effects.\n\n    :cache-key-fn\n\n      A function that calculates a String cache key for the args passed to the\n      collapser. Optional, defaults to a function returning nil, i.e. no caching.\n      This function should be completely free of side effects.\n\n    :init-fn\n\n      A function that takes a definition map and HystrixCollapser$Setter which should return\n      a HystrixCollapser$Setter (usually the one passed in) to ultimately be passed to the\n      constructor of the HystrixCollapser. For example,\n\n          (fn [_ setter]\n            (.andCollapserPropertiesDefaults setter ...))\n\n      This is your escape hatch into raw Hystrix. Please see additional notes about :init-fn\n      above. They apply to collapsers as well.\n\n  The com.netflix.hystric.core/defcollapser macro is a helper for defining this map and storing it\n  in a callable var.\n  \"\n  (:require [clojure.set :as set])\n  (:import [java.util.concurrent Future]\n           [com.netflix.hystrix\n              HystrixExecutable\n              HystrixCommand\n              HystrixCommand$Setter\n              HystrixCollapser\n              HystrixCollapser$Scope\n              HystrixCollapser$Setter\n              HystrixCollapser$CollapsedRequest]\n           [com.netflix.hystrix.strategy.concurrency\n             HystrixRequestContext]))\n\n(set! *warn-on-reflection* true)\n\n(defmacro ^:private key-fn\n  \"Make a function that creates keys of the given class given one of:\n\n      * an instance of class\n      * a string name\n      * a keyword name\n  \"\n  [class]\n  (let [s (-> class name (str \"$Factory/asKey\") symbol)]\n    `(fn [key-name#]\n       (cond\n         (nil? key-name#)\n          nil\n         (instance? ~class key-name#)\n           key-name#\n         (keyword? key-name#)\n           (~s (name key-name#))\n         (string? key-name#)\n           (~s key-name#)\n         :else\n           (throw (IllegalArgumentException. (str \"Don't know how to make \" ~class \" from \" key-name#)))))))\n\n(def command-key\n  \"Given a string or keyword, returns a HystrixCommandKey. nil and HystrixCommandKey instances\n  are returned unchanged.\n\n  This function is rarely needed since most hystrix-clj functions will do this automatically.\n\n  See:\n    com.netflix.hystrix.HystrixCommandKey\n  \"\n  (key-fn com.netflix.hystrix.HystrixCommandKey))\n\n(def group-key\n  \"Given a string or keyword, returns a HystrixCommandGroupKey. nil and HystrixCommandGroupKey\n  instances are returned unchanged.\n\n  This function is rarely needed since most hystrix-clj functions will do this automatically.\n\n  See:\n    com.netflix.hystrix.HystrixCommandGroupKey\n  \"\n  (key-fn com.netflix.hystrix.HystrixCommandGroupKey))\n\n(def thread-pool-key\n  \"Given a string or keyword, returns a HystrixThreadPoolGroupKey. nil and HystrixThreadPoolKey\n  instances are returned unchanged.\n\n  This function is rarely needed since most hystrix-clj functions will do this automatically.\n\n  See:\n    com.netflix.hystrix.HystrixThreadPoolKey\n  \"\n  (key-fn com.netflix.hystrix.HystrixThreadPoolKey))\n\n(def collapser-key\n  \"Given a string or keyword, returns a HystrixCollapserKey. nil and HystrixCollapserKey\n  instances are returned unchanged.\n\n  This function is rarely needed since most hystrix-clj functions will do this automatically.\n\n  See:\n    com.netflix.hystrix.HystrixCollapserKey\n  \"\n  (key-fn com.netflix.hystrix.HystrixCollapserKey))\n\n(defn ^HystrixCollapser$Scope collapser-scope\n  [v]\n  (cond\n    (instance? HystrixCollapser$Scope v)\n      v\n    (= :request v)\n      HystrixCollapser$Scope/REQUEST\n    (= :global v)\n      HystrixCollapser$Scope/GLOBAL\n    :else\n      (throw (IllegalArgumentException. (str \"Don't know how to make collapser scope from '\" v \"'\")))))\n\n(defn- required-key\n  [k p msg]\n  (fn [d]\n    (when-not (contains? d k)\n      (throw (IllegalArgumentException. (str k \" is required.\"))))\n    (when-not (p (get d k))\n      (throw (IllegalArgumentException. (str k \" \" msg \".\"))))\n    d))\n\n(defn- optional-key\n  [k p msg]\n  (fn [d]\n    (if-let [v (get d k)]\n      (when-not (p v)\n        (throw (IllegalArgumentException. (str k \" \" msg \".\")))))\n    d))\n(defn- required-fn [k] (required-key k ifn? \"must be a function\"))\n(defn- optional-fn [k] (optional-key k ifn? \"must be a function\"))\n\n;################################################################################\n\n(defmulti normalize\n  \"Given a definition map, verify and normalize it, expanding shortcuts to fully-qualified objects, etc.\n\n  Throws IllegalArgumentException if any constraints for the definition map are violated.\n  \"\n  (fn [definition] (:type definition)))\n\n(defmulti instantiate* (fn [definition & _] (:type definition)))\n\n;################################################################################\n\n(def ^{:dynamic true :tag HystrixCommand} *command*\n  \"A dynamic var which is bound to the HystrixCommand instance during execution of\n  :run-fn and :fallback-fn.\n\n  It's occasionally useful, especially for fallbacks, to base the result on the state of\n  the comand. The fallback might vary based on whether it was triggered by an application\n  error versus a timeout.\n\n  Note: As always with dynamic vars be careful about scoping. This binding only holds for\n  the duration of the :run-fn or :fallback-fn.\n  \"\n  nil)\n\n;################################################################################\n\n(defmacro with-request-context\n  \"Executes body within a new Hystrix Context.\n\n  Initializes a new HystrixRequestContext, executes the code and then shuts down the\n  context. Evaluates to the result of body.\n\n  Example:\n\n    (with-request-context\n      (... some code that uses Hystrix ...))\n\n  See:\n    com.netflix.hystrix.strategy.concurrency.HystrixRequestContext\n  \"\n  [& body]\n  `(let [context# (HystrixRequestContext/initializeContext)]\n     (try\n       ~@body\n       (finally\n         (.shutdown context#)))))\n\n(defn command\n  \"Helper function that takes a definition map for a HystrixCommand and returns a normalized\n  version ready for use with execute and queue.\n\n  See com.netflix.hystrix.core ns documentation for valid keys.\n\n  See:\n    com.netflix.hystrix.core/defcommand\n  \"\n  [options-map]\n  (-> options-map\n    (assoc :type :command)\n    normalize))\n\n(defn- split-def-meta\n  \"split meta map out of def-style args list\"\n  [opts]\n  (let [doc?      (string? (first opts))\n        m         (if doc? {:doc (first opts)} {})\n        opts      (if doc? (rest opts) opts)\n\n        attrs?    (map? (first opts))\n        m         (if attrs? (merge (first opts) m) m)\n        opts      (if attrs? (rest opts) opts)]\n    [m opts]))\n\n(defn- extract-hystrix-command-options\n  [meta-map]\n  (let [key-map {:hystrix/cache-key-fn    :cache-key-fn\n                 :hystrix/fallback-fn     :fallback-fn\n                 :hystrix/group-key       :group-key\n                 :hystrix/command-key     :command-key\n                 :hystrix/thread-pool-key :thread-pool-key\n                 :hystrix/init-fn         :init-fn }]\n    (set/rename-keys (select-keys meta-map (keys key-map)) key-map)))\n\n(defmacro defcommand\n  \"A macro with the same basic form as clojure.core/defn exception that it wraps the body\n  of the function in a HystrixCommand. This allows an existing defn to be turned into\n  a command by simply change \\\"defn\\\" to \\\"defcommand\\\".\n\n  Additional command options can be provided in the defn attr-map, qualifying their keys with\n  the :hystrix namespace, e.g. :thread-pool-key becomes :hystrix/thread-pool-key. Obviously,\n  :hystrix/run-fn is ignored since it's inferred from the body of the macro.\n\n  The *var* defined by this macro can be passed to the execute and queue functions as if\n  it were a HystrixCommand definition map. The complete definition map is stored under the\n  :hystrix key in the var's metadata.\n\n  See com.netflix.hystrix.core ns documentation for valid keys.\n\n  Example:\n\n    (defcommand search\n      \\\"Fault tolerant search\\\"\n      [term]\n      ... execute service request and return vector of results ...)\n\n    ; Same as above, but add fallback and caching\n    (defcommand search\n      \\\"Fault tolerant search\\\"\n      {:hystrix/cache-key-fn identity\n       :hystrix/fallback-fn  (constantly []))}\n      [term]\n      ... execute service request and return vector of results ...)\n\n    ; Call it like a normal function\n    (search \\\"The Big Lebowski\\\")\n    ;=>  [... vector of results ...]\n\n    ; Asynchronously execute the search command\n    (queue #'search \\\"Fargo\\\")\n    ;=> a deref-able future\n  \"\n  {:arglists '([name doc-string? attr-map? [params*] & body])}\n  [name & opts]\n  (let [command-key         (str *ns* \"/\" name )\n        group-key           (str *ns*)\n        [m body]            (split-def-meta opts)\n        params              (if (vector? (first body))\n                              (list (first body))\n                              (map first body))\n        m                   (if-not (contains? m :arglists)\n                              (assoc m :arglists ('quote `(~params)))\n                              m)]\n    `(let [meta-options# (#'com.netflix.hystrix.core/extract-hystrix-command-options ~m)\n           run-fn#       (fn ~name ~@body)\n           command-map#  (com.netflix.hystrix.core/command (merge {:command-key   ~command-key\n                                                                   :group-key     ~group-key\n                                                                   :run-fn        run-fn# }\n                                                                  meta-options#))]\n       (def ~(with-meta name m)\n         (fn [& args#]\n           (apply com.netflix.hystrix.core/execute command-map# args#)))\n       (alter-meta! (var ~name) assoc :hystrix command-map#)\n       (var ~name))))\n\n(defn- extract-hystrix-collapser-options\n  [meta-map]\n  (let [key-map {:hystrix/collapser-key :collapser-key\n                 :hystrix/shard-fn      :shard-fn\n                 :hystrix/scope         :scope\n                 :hystrix/cache-key-fn  :cache-key-fn\n                 :hystrix/init-fn       :init-fn }]\n    (set/rename-keys (select-keys meta-map (keys key-map)) key-map)))\n\n(defn collapser\n  \"Helper function that takes a definition map for a HystrixCollapser and returns a normalized\n  version ready for use with execute and queue.\n\n  See com.netflix.hystrix.core ns documentation for valid keys.\n\n  See:\n    com.netflix.hystrix.core/defcollapser\n  \"\n  [{:keys [collapser-key] :as options-map}]\n  (let [result (-> options-map\n                 (assoc :type :collapser)\n                 normalize)]\n    result))\n\n(defmacro defcollapser\n  \"Define a new collapser bound to the given var with a collapser key created from the current\n  namespace and the var name. Like clojure.core/defn, takes an optional doc string and metadata\n  map. The form is similar to defn except that a body for both :map-fn and :collapse-fn must be\n  provided:\n\n    (defcollapser my-collapser\n      \\\"optional doc string\\\"\n      {... optional attr map with var metadata ...}\n      (collapse [arg-lists] ... body of :collapse-fn ...)\n      (map      [arg-lists batch-result] ... body of :map-fn ...))\n\n  Additional collapser options can be provided in the attr-map, qualifying their keys with\n  the :hystrix namespace, e.g. :scope becomes :hystrix/scope. Obviously,\n  :hystrix/collapse-fn and :hystrix/map-fn are ignored since they're inferred from the body\n  of the macro.\n\n  See com.netflix.hystrix.core ns documentation for valid keys.\n\n  Example:\n\n     (ns my-namespace\n       :require  com.netflix.hystrix.core :refer [defcommand defcollapser instantiate execute queue])\n\n    ; Suppose there's an existing multi-search command that takes a sequence of multiple search\n    ; terms and returns a vector of vector of search results with a single server request.\n    (defcommand multi-search ...)\n\n    ; Now we can define single-term search as a collapser that will collapse multiple\n    ; in-flight search requests into a single multi-term search request to the server\n    (defcollapser search\n      \\\"Collapsing single-term search command\\\"\n      (collapse [arg-lists]\n        ; Create a multi-search command, passing individual terms as a seq of args\n        (instantiate multi-search (map first arg-lists)))\n      (map [arg-lists batch-result]\n        ; Map from input args to results. Here we assume order is preserve by\n        ; multi-search so we can return the result list directly\n        batch-result))\n\n    ; The search collapser is now defined. It has a collapser key of \\\"my-namespace/search\\\".\n    ; This is used for configuration and metrics.\n\n    ; Syncrhonously execute the search collapser\n    (search \\\"The Hudsucker Proxy\\\")\n    ;=> [... vector of results ...]\n\n    ; Asynchronously execute the search collapser\n    (queue search \\\"Raising Arizona\\\")\n    ;=> a deref-able future\n  \"\n  {:arglists '([name doc-string? attr-map?\n                (collapse [arg-lists] :collapse-fn body)\n                (map      [arg-lists batch-result] :map-fn body)])}\n  [name & opts]\n  (let [full-name (str *ns* \"/\" name)\n        [m fns]   (split-def-meta opts)\n        _         (when-not (= 2 (count fns))\n                    (throw (IllegalArgumentException. \"Expected collapse and map forms.\")))\n        getfn     (fn [s] (first (filter #(= s (first %)) fns)))\n        [_ collapse-args & collapse-body] (getfn 'collapse)\n        [_ map-args      & map-body]      (getfn 'map)]\n    `(let [meta-options# (#'com.netflix.hystrix.core/extract-hystrix-collapser-options ~m)\n           map-fn#       (fn ~map-args ~@map-body)\n           collapse-fn#  (fn ~collapse-args ~@collapse-body)\n           def-map# (com.netflix.hystrix.core/collapser (merge {:collapser-key ~full-name\n                                                                :map-fn map-fn#\n                                                                :collapse-fn collapse-fn# }\n                                                               meta-options#))]\n       (def ~(with-meta name m)\n         (fn [& args#]\n           (apply com.netflix.hystrix.core/execute def-map# args#)))\n       (alter-meta! (var ~name) assoc :hystrix def-map#)\n       (var ~name))))\n\n(defn ^HystrixExecutable instantiate\n  \"Given a normalized definition map for a command or collapser, 'compiles' it into a HystrixExecutable object\n  that can be executed, queued, etc. This function should rarely be used. Use execute and queue\n  instead.\n\n  definition may be any of:\n\n    * A var created with defcommand\n    * A var created with defcollapser\n    * A normalized definition map for a command\n    * A HystrixExecutable instance and no additional arguments\n\n  One typical use case for this function is to create a batch command in the :collapse-fn of a collapser. Another is to get an actual HystrixCommand instance to get access to additional methods\n  it provides.\n\n  See:\n    com.neflix.hystrix.core/normalize\n    com.neflix.hystrix.core/execute\n    com.neflix.hystrix.core/queue\n  \"\n  {:arglists '[[defcommand-var & args]\n               [defcollapser-var & args]\n               [definition-map & args]\n               [HystrixExecutable] ]}\n  [definition & args]\n  (cond\n    (var? definition)\n      (if-let [hm (-> definition meta :hystrix)]\n        (apply instantiate* hm  args)\n        (throw (IllegalArgumentException. (str \"Couldn't find :hystrix metadata on var \" definition))))\n\n    (map? definition)\n      (apply instantiate* definition args)\n\n    (instance? HystrixExecutable definition)\n      (if (empty? args)\n        definition\n        (throw (IllegalArgumentException. \"Trailing args when executing raw HystrixExecutable\")))\n\n    :else\n      (throw (IllegalArgumentException. (str \"Don't know how to make instantiate HystrixExecutable from: \" definition)))))\n\n(defn execute\n  \"Synchronously execute the command or collapser specified by the given normalized definition with\n  the given arguments. Returns the result of :run-fn.\n\n  NEVER EXECUTE A HystrixExecutable MORE THAN ONCE.\n\n  See:\n    http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#execute()\n  \"\n  [definition & args]\n  (.execute ^HystrixExecutable (apply instantiate definition args)))\n\n(defprotocol QueuedCommand\n  \"Protocol implemented by the result of com.netflix.hystrix.core/queue\"\n  (instance [this] \"Returns the raw HystrixExecutable instance created by the queued command\"))\n\n(defn- queued-command [^HystrixExecutable instance ^Future future]\n  (reify\n    QueuedCommand\n      (instance [this] instance)\n\n    Future\n      (get [this] (.get future))\n      (get [this timeout timeunit] (.get future timeout timeunit))\n      (isCancelled [this] (.isCancelled future))\n      (isDone [this] (.isDone future))\n      (cancel [this may-interrupt?] (.cancel future may-interrupt?))\n\n    clojure.lang.IDeref\n      (deref [this] (.get future))))\n\n(defn queue\n  \"Asynchronously queue the command or collapser specified by the given normalized definition with\n  the given arguments. Returns an object which implements both java.util.concurrent.Future and\n  clojure.lang.IDeref.\n\n  The returned object also implements the QueuedCommand protocol.\n\n  If definition is already a HystrixExecutable and no args are given, queues it and returns\n  the same object as described above. NEVER QUEUE A HystrixExecutable MORE THAN ONCE.\n\n  Examples:\n\n    (let [qc (queue my-command 1 2 3)]\n      ... do something else ...\n      ; wait for result\n      @qc)\n\n  See:\n    http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#queue()\n  \"\n  [definition & args]\n  (let [^HystrixExecutable instance (apply instantiate definition args)]\n    (queued-command instance (.queue instance))))\n\n(defn observe\n  \"Asynchronously execute the command or collapser specified by the given normalized definition\n  with the given arguments. Returns an rx.Observable which can be subscribed to.\n\n  Note that this will eagerly begin execution of the command, even if there are no subscribers.\n  Use observe-later for lazy semantics.\n\n  If definition is already a HystrixExecutable and no args are given, observes it and returns\n  an Observable as described above. NEVER OBSERVE A HystrixExecutable MORE THAN ONCE.\n\n  See:\n    http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#observe()\n    http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCollapser.html#observe()\n    http://netflix.github.io/RxJava/javadoc/rx/Observable.html\n  \"\n  [definition & args]\n  (let [^HystrixExecutable instance (apply instantiate definition args)]\n    (.observe instance)))\n\n(defprotocol ^:private ObserveLater\n  \"A protocol solely to eliminate reflection warnings because .toObservable\n  can be found on both HystrixCommand and HystrixCollapser, but not in their\n  common base class HystrixExecutable.\"\n  (^:private observe-later* [this])\n  (^:private observe-later-on* [this scheduler]))\n\n(extend-protocol ObserveLater\n  HystrixCommand\n    (observe-later* [this] (.toObservable this))\n    (observe-later-on* [this scheduler] (.observeOn (.toObservable this) scheduler))\n  HystrixCollapser\n    (observe-later* [this] (.toObservable this))\n    (observe-later-on* [this scheduler] (.observeOn (.toObservable this) scheduler)))\n\n(defn observe-later\n  \"Same as #'com.netflix.hystrix.core/observe, but command execution does not begin until the\n  returned Observable is subscribed to.\n\n  See:\n    http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#toObservable())\n    http://netflix.github.io/RxJava/javadoc/rx/Observable.html\n  \"\n  [definition & args]\n  (observe-later* (apply instantiate definition args)))\n\n(defn observe-later-on\n  \"Same as #'com.netflix.hystrix.core/observe-later but an explicit scheduler can be provided\n  for the callback.\n\n  See:\n    com.netflix.hystrix.core/observe-later\n    com.netflix.hystrix.core/observe\n    http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#toObservable(Scheduler)\n    http://netflix.github.io/RxJava/javadoc/rx/Observable.html\n  \"\n  [definition scheduler & args]\n  (observe-later-on* (apply instantiate definition args) scheduler))\n\n;################################################################################\n; :command impl\n\n(defmethod normalize :command\n  [definition]\n  (-> definition\n    ((required-fn :run-fn))\n    ((optional-fn :fallback-fn))\n    ((optional-fn :cache-key-fn))\n    ((optional-fn :init-fn))\n\n    (update-in [:group-key] group-key)\n    (update-in [:command-key] command-key)\n    (update-in [:thread-pool-key] thread-pool-key)))\n\n(defmethod instantiate* :command\n  [{:keys [group-key command-key thread-pool-key\n           run-fn fallback-fn cache-key-fn\n           init-fn] :as def-map} & args]\n  (let [setter (-> (HystrixCommand$Setter/withGroupKey group-key)\n                 (.andCommandKey    command-key)\n                 (.andThreadPoolKey thread-pool-key))\n        setter (if init-fn\n                 (init-fn def-map setter)\n                 setter)]\n    (when (not (instance? HystrixCommand$Setter setter))\n      (throw (IllegalStateException. (str \":init-fn didn't return HystrixCommand$Setter instance\"))))\n    (proxy [HystrixCommand] [^HystrixCommand$Setter setter]\n      (run []\n        (binding [*command* this]\n          (apply run-fn args)))\n      (getFallback []\n        (if fallback-fn\n          (binding [*command* this]\n            (apply fallback-fn args))\n          (throw (UnsupportedOperationException. \"No :fallback-fn provided\"))))\n      (getCacheKey [] (if cache-key-fn\n                        (apply cache-key-fn args))))))\n\n\n;################################################################################\n; :collapser impl\n\n(defmethod normalize :collapser\n  [definition]\n  (-> definition\n    ((required-fn :collapse-fn))\n    ((required-fn :map-fn))\n    ((optional-fn :shard-fn))\n    ((optional-fn :cache-key-fn))\n    ((optional-fn :init-fn))\n\n    (update-in [:collapser-key] collapser-key)\n    (update-in [:scope]         (fnil collapser-scope HystrixCollapser$Scope/REQUEST))))\n\n(defn- collapsed-request->arg-list\n  [^HystrixCollapser$CollapsedRequest request]\n  (.getArgument request))\n\n(defmethod instantiate* :collapser\n  [{:keys [collapser-key scope\n           collapse-fn map-fn shard-fn cache-key-fn\n           init-fn] :as def-map} & args]\n  (let [setter (-> (HystrixCollapser$Setter/withCollapserKey collapser-key)\n                 (.andScope scope))\n        setter (if init-fn\n                 (init-fn def-map setter)\n                 setter)]\n    (when (not (instance? HystrixCollapser$Setter setter))\n      (throw (IllegalStateException. (str \":init-fn didn't return HystrixCollapser$Setter instance\"))))\n    (proxy [HystrixCollapser] [^HystrixCollapser$Setter setter]\n      (getCacheKey [] (if cache-key-fn\n                        (apply cache-key-fn args)))\n\n      (getRequestArgument [] args)\n\n      (createCommand [requests]\n        (collapse-fn (map collapsed-request->arg-list requests)))\n\n      (shardRequests [requests]\n        (if shard-fn\n          [requests] ; TODO implement sharding\n          [requests]))\n\n      (mapResponseToRequests [batch-response requests]\n        (let [arg-lists        (map collapsed-request->arg-list requests)\n              mapped-responses (map-fn arg-lists batch-response)]\n          (if-not (= (count requests) (count mapped-responses))\n            (throw (IllegalStateException.\n                     (str \":map-fn of collapser '\" collapser-key\n                          \"' did not return a result for each request. Expected \" (count requests)\n                          \", got \" (count mapped-responses)))))\n          (doseq [[^HystrixCollapser$CollapsedRequest request response] (map vector requests mapped-responses)]\n            (if (instance? Exception response)\n              (.setException request ^Exception response)\n              (.setResponse request response))))))))\n"
  },
  {
    "path": "hystrix-contrib/hystrix-clj/src/test/clojure/com/netflix/hystrix/core_test.clj",
    "content": ";\n; Copyright 2016 Netflix, Inc.\n;\n; Licensed under the Apache License, Version 2.0 (the \"License\");\n; you may not use this file except in compliance with the License.\n; You may obtain a copy of the License at\n;\n;     http://www.apache.org/licenses/LICENSE-2.0\n;\n; Unless required by applicable law or agreed to in writing, software\n; distributed under the License is distributed on an \"AS IS\" BASIS,\n; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n; See the License for the specific language governing permissions and\n; limitations under the License.\n;\n\n(ns com.netflix.hystrix.core-test\n  (:use com.netflix.hystrix.core)\n  (:require [clojure.test :refer [deftest testing is are use-fixtures]])\n  (:import [com.netflix.hystrix Hystrix HystrixExecutable]\n           [com.netflix.hystrix.strategy.concurrency HystrixRequestContext]\n           [com.netflix.hystrix.exception HystrixRuntimeException]))\n\n; reset hystrix after each execution, for consistency and sanity\n(defn reset-fixture\n  [f]\n  (try\n    (f)\n    (finally\n      (Hystrix/reset))))\n\n(use-fixtures :once reset-fixture)\n\n; wrap each test in hystrix context\n(defn request-context-fixture\n  [f]\n  (try\n    (HystrixRequestContext/initializeContext)\n    (f)\n    (finally\n      (when-let [c (HystrixRequestContext/getContextForCurrentThread)]\n        (.shutdown c)))))\n\n(use-fixtures :each request-context-fixture)\n\n(deftest test-command-key\n  (testing \"returns nil when input is nil\"\n    (is (nil? (command-key nil))))\n\n  (testing \"returns existing key unchanged\"\n    (let [k (command-key \"foo\")]\n      (is (identical? k (command-key k)))))\n\n  (testing \"Makes a key from a string\"\n    (let [^com.netflix.hystrix.HystrixCommandKey k (command-key \"foo\")]\n      (is (instance? com.netflix.hystrix.HystrixCommandKey k))\n      (is (= \"foo\" (.name k)))))\n\n  (testing \"Makes a key from a keyword\"\n    (let [^com.netflix.hystrix.HystrixCommandKey k (command-key :bar)]\n      (is (instance? com.netflix.hystrix.HystrixCommandKey k))\n      (is (= \"bar\" (.name k))))))\n\n(deftest test-normalize-collapser-scope\n  (testing \"throws on nil\"\n    (is (thrown? IllegalArgumentException (collapser-scope nil))))\n  (testing \"throws on unknown\"\n    (is (thrown? IllegalArgumentException (collapser-scope :foo))))\n  (testing \"Returns a scope unchanged\"\n    (is (= com.netflix.hystrix.HystrixCollapser$Scope/REQUEST\n           (collapser-scope com.netflix.hystrix.HystrixCollapser$Scope/REQUEST))))\n  (testing \"Returns a request scope\"\n    (is (= com.netflix.hystrix.HystrixCollapser$Scope/REQUEST\n           (collapser-scope :request))))\n  (testing \"Returns a global scope\"\n    (is (= com.netflix.hystrix.HystrixCollapser$Scope/GLOBAL\n           (collapser-scope :global)))))\n\n(deftest test-normalize-command\n  (testing \"throws if :init-fn isn't a fn\"\n    (is (thrown-with-msg? IllegalArgumentException #\"^.*init-fn.*$\"\n                          (normalize {:type :command\n                                      :run-fn +\n                                      :init-fn 999})))))\n\n(deftest test-normalize-collapser\n  (testing \"throws if :init-fn isn't a fn\"\n    (is (thrown-with-msg? IllegalArgumentException #\"^.*init-fn.*$\"\n                          (normalize {:type :collapser\n                                      :collapse-fn (fn [& args])\n                                      :map-fn (fn [& args])\n                                      :init-fn \"foo\"})))))\n\n(deftest test-instantiate\n  (let [base-def {:type :command\n                  :group-key :my-group\n                  :command-key :my-command\n                  :run-fn + }]\n    (testing \"makes a HystrixCommand\"\n      (let [c (instantiate (normalize base-def))]\n        (is (instance? com.netflix.hystrix.HystrixCommand c))))\n\n    (testing \"makes a HystrixCommand and calls :init-fn\"\n      (let [called (atom nil)\n            init-fn (fn [d s] (reset! called [d s]) s)\n            c (instantiate (normalize (assoc base-def :init-fn init-fn)))\n            [d s] @called]\n        (is (not (nil? @called)))\n        (is (map? d))\n        (is (instance? com.netflix.hystrix.HystrixCommand$Setter s))))\n\n    (testing \"makes a HystrixCommand that executes :run-fn with given args\"\n      (let [c (instantiate (normalize base-def) 99 42)]\n        (is (= 141 (.execute c)))))\n\n    (testing \"makes a HystrixCommand that executes :fallback-fn with given args\"\n      (let [c (instantiate (normalize (assoc base-def\n                                             :run-fn (fn [& args] (throw (IllegalStateException.)))\n                                             :fallback-fn -))\n                           99 42)]\n        (is (= (- 99 42) (.execute c)))))\n\n    (testing \"makes a HystrixCommand that implements getCacheKey\"\n      (with-request-context\n        (let [call-count (atom 0) ; make sure run-fn is only called once\n               test-def (normalize (assoc base-def\n                                     :run-fn       (fn [arg] (swap! call-count inc) (str arg \"!\"))\n                                     :cache-key-fn (fn [arg] arg)))\n               result1 (.execute (instantiate test-def \"hi\"))\n               result2 (.execute (instantiate test-def \"hi\"))]\n          (is (= \"hi!\" result1 result2))\n          (is (= 1 @call-count))))))\n  (testing \"throws if :hystrix metadata isn't found in a var\"\n    (is (thrown? IllegalArgumentException\n                 (instantiate #'map))))\n  (testing \"throws if it doesn't know what to do\"\n    (is (thrown? IllegalArgumentException\n                 (instantiate [1 2 2])))))\n\n(deftest test-execute\n  (let [base-def {:type :command\n                  :group-key :my-group\n                  :command-key :my-command }]\n    (testing \"executes a HystrixCommand\"\n      (is (= \"hello-world\")\n          (execute (instantiate (normalize (assoc base-def :run-fn str))\n                                \"hello\" \"-\" \"world\"))))\n\n    (testing \"throws HystrixRuntimeException if called twice on same instance\"\n      (let [instance (instantiate (normalize (assoc base-def :run-fn str)) \"hi\")]\n        (is (thrown? HystrixRuntimeException\n                     (execute instance)\n                     (execute instance)))))\n\n    (testing \"throws if there are trailing args\"\n      (is (thrown? IllegalArgumentException\n                   (execute (instantiate (normalize base-def)) \"hello\" \"-\" \"world\"))))\n\n    (testing \"instantiates and executes a command\"\n      (is (= \"hello-world\")\n          (execute (normalize (assoc base-def :run-fn str))\n                   \"hello\" \"-\" \"world\")))))\n\n(deftest test-queue\n  (let [base-def {:type :command\n                  :group-key :my-group\n                  :command-key :my-command\n                  :run-fn + }]\n\n    (testing \"queues a HystrixCommand\"\n      (is (= \"hello-world\")\n          (.get (queue (instantiate (normalize (assoc base-def :run-fn str))\n                                    \"hello\" \"-\" \"world\")))))\n\n    (testing \"throws if there are trailing args\"\n      (is (thrown? IllegalArgumentException\n                   (queue (instantiate (normalize base-def)) \"hello\" \"-\" \"world\"))))\n\n    (testing \"instantiates and queues a command\"\n      (let [qc (queue (normalize (assoc base-def :run-fn str)) \"hello\" \"-\" \"world\")]\n        (is (instance? HystrixExecutable (instance qc)))\n        (is (future? qc))\n        (is (= \"hello-world\" (.get qc) @qc))\n        (is (.isDone qc))))))\n\n(defn ^:private wait-for-observable\n  [^rx.Observable o]\n  (-> o .toBlocking .single))\n\n(deftest test-observe\n  (let [base-def {:type :command\n                  :group-key :my-group\n                  :command-key :my-command\n                  :run-fn + }]\n    (testing \"observes a HystrixCommand\"\n      (is (= 99\n             (-> (instantiate (normalize base-def) 11 88)\n                 observe\n                 wait-for-observable))))\n    (testing \"throws if there are trailing args\"\n      (is (thrown? IllegalArgumentException\n                   (observe (instantiate (normalize base-def)) 10 23))))\n    (testing \"instantiates and observes a command\"\n      (let [o (observe (normalize base-def) 75 19 23)]\n        (is (instance? rx.Observable o))\n        (is (= (+ 75 19 23)\n               (wait-for-observable o)))))))\n\n(deftest test-observe-later\n  (let [base-def {:type :command\n                  :group-key :my-group\n                  :command-key :my-command\n                  :run-fn + }]\n    (testing \"observes a HystrixCommand\"\n      (is (= 99\n             (-> (instantiate (normalize base-def) 11 88)\n                 observe-later\n                 wait-for-observable))))\n    (testing \"throws if there are trailing args\"\n      (is (thrown? IllegalArgumentException\n                   (observe-later (instantiate (normalize base-def)) 10 23))))\n    (testing \"instantiates and observes a command\"\n      (let [o (observe-later (normalize base-def) 75 19 23)]\n        (is (instance? rx.Observable o))\n        (is (= (+ 75 19 23)\n               (wait-for-observable o)))))\n    (testing \"observes command with a Scheduler\"\n      (let [o (observe-later-on (normalize base-def)\n                                (rx.schedulers.Schedulers/newThread)\n                                75 19 23)]\n        (is (instance? rx.Observable o))\n        (is (= (+ 75 19 23)\n               (wait-for-observable o)))))))\n\n(deftest test-this-command-binding\n  (let [base-def {:type :command\n                  :group-key :test-this-command-binding-group\n                  :command-key :test-this-command-binding\n                  }]\n    (testing \"this is bound while :run-fn is executing\"\n      (let [captured (atom nil)\n            command-def (normalize (assoc base-def\n                                          :run-fn (fn []\n                                                    (reset! captured *command*))))\n            command (instantiate command-def)]\n        (.execute command)\n        (is (identical? command @captured))))\n\n\n    (testing \"this is bound while :fallback-fn is executing\"\n      (let [captured (atom nil)\n            command-def (normalize (assoc base-def\n                                          :run-fn (fn [] (throw (Exception. \"FALLBACK!\")))\n                                          :fallback-fn (fn [] (reset! captured *command*))\n                                          ))\n            command (instantiate command-def)]\n        (.execute command)\n        (is (identical? command @captured))))))\n\n(deftest test-collapser\n  ; These atoms are only for testing. In real life, collapser functions should *never*\n  ; have side effects.\n  (let [batch-calls (atom [])\n        map-fn-calls (atom [])\n        collapse-fn-calls (atom [])\n        to-upper-batch  (fn [xs] (mapv #(.toUpperCase ^String %) xs))\n        ; Define a batch version of to-upper\n        command (normalize {:type        :command\n                            :group-key   :my-group\n                            :command-key :to-upper-batcher\n                            :run-fn      (fn [xs]\n                                           (swap! batch-calls conj (count xs))\n                                           (to-upper-batch xs))})\n\n        ; Define a collapser for to-upper\n        collapser (normalize {:type          :collapser\n                              :collapser-key :to-upper-collapser\n                              :collapse-fn   (fn [arg-lists]\n                                               (swap! collapse-fn-calls conj (count arg-lists))\n                                               ; batch to-upper takes a list of strings, i.e. the first/only\n                                               ; arg of each request\n                                               (instantiate command (mapv first arg-lists)))\n                              :map-fn        (fn [arg-lists uppered]\n                                               (swap! map-fn-calls conj (count arg-lists))\n                                               ; batch to-upper returns results in same order as input so\n                                               ; we can just to a direct mapping without looking in the\n                                               ; results.\n                                               uppered) })]\n    (testing \"that it actually works\"\n      (let [n 100\n            inputs           (mapv #(str \"xyx\" %) (range n))\n            expected-results (to-upper-batch inputs)\n            to-upper         (partial queue collapser)\n            queued           (doall (map (fn [x]\n                                           (Thread/sleep 1)\n                                           (to-upper x))\n                                         inputs))\n            results          (doall (map deref queued))]\n        (println \"Got collapses with sizes:\" @collapse-fn-calls)\n        (println \"Got maps with sizes:\" @map-fn-calls)\n        (println \"Got batches with sizes:\" @batch-calls)\n        (is (= n (count expected-results) (count results)))\n        (is (= expected-results results))\n        (is (not (empty? @collapse-fn-calls)))\n        (is (not (empty? @map-fn-calls)))\n        (is (not (empty? @batch-calls)))))))\n\n(defcommand my-fn-command\n  \"A doc string\"\n  {:meta :data\n   :hystrix/fallback-fn (constantly 500)}\n  [a b]\n  (+ a b))\n\n(defcommand my-overload-fn-command\n  \"A doc string\"\n  {:meta :data\n   :hystrix/fallback-fn (constantly 500)}\n  ([a b]\n     (+ a b))\n  ([a b c]\n     (+ a b c)))\n\n(deftest test-defcommand\n  (let [hm (-> #'my-fn-command meta :hystrix)]\n    (testing \"defines a fn in a var\"\n      (is (fn? my-fn-command))\n      (is (map? hm))\n      (is (= \"com.netflix.hystrix.core-test/my-fn-command\" (.name (:command-key hm))))\n      (is (= \"com.netflix.hystrix.core-test\" (.name (:group-key hm))))\n      (is (= :data (-> #'my-fn-command meta :meta)))\n      (= 500 ((:fallback-fn hm))))\n    (testing \"defines a functioning command\"\n      (is (= 99 (my-fn-command 88 11)))\n      (is (= 100 (execute #'my-fn-command 89 11)))\n      (is (= 101 (deref (queue #'my-fn-command 89 12))))\n      (is (= 103 (wait-for-observable (observe #'my-fn-command 90 13))))\n      (is (= 105 (wait-for-observable (observe-later #'my-fn-command 91 14))))\n      (is (= 107 (wait-for-observable (observe-later-on #'my-fn-command\n                                                        (rx.schedulers.Schedulers/newThread)\n                                                        92 15)))))\n    (testing \"overload functioning command\"\n      (is (= 99 (my-overload-fn-command 88 11)))\n      (is (= 100 (my-overload-fn-command 88 11 1)))\n      (is (= 100 (execute #'my-overload-fn-command 89 11)))\n      (is (= 100 (execute #'my-overload-fn-command 88 11 1)))\n      (is (= 101 (deref (queue #'my-overload-fn-command 89 12))))\n      (is (= 102 (deref (queue #'my-overload-fn-command 89 12 1))))\n      (is (= 103 (wait-for-observable (observe #'my-overload-fn-command 90 13))))\n      (is (= 104 (wait-for-observable (observe #'my-overload-fn-command 90 13 1))))\n      (is (= 105 (wait-for-observable (observe-later #'my-overload-fn-command 91 14))))\n      (is (= 106 (wait-for-observable (observe-later #'my-overload-fn-command 91 14 1))))\n      (is (= 107 (wait-for-observable (observe-later-on #'my-overload-fn-command\n                                                        (rx.schedulers.Schedulers/newThread)\n                                                        92 15))))\n      (is (= 108 (wait-for-observable (observe-later-on #'my-overload-fn-command\n                                                        (rx.schedulers.Schedulers/newThread)\n                                                        92 15 1)))))))\n\n(defcollapser my-collapser\n  \"a doc string\"\n  {:meta :data}\n  (collapse [arg-lists] \"collapse\")\n  (map      [batch-result arg-lists] \"map\"))\n\n(deftest test-defcollapser\n  (let [hm (-> #'my-collapser meta :hystrix)]\n    (testing \"defines a collapser in a var\"\n      (is (fn? my-collapser))\n      (is (map? hm))\n      (is (= \"com.netflix.hystrix.core-test/my-collapser\" (.name (:collapser-key hm))))\n      (is (= :collapser (:type hm)))\n      (is (= \"a doc string\" (-> #'my-collapser meta :doc)))\n      (is (= :data (-> #'my-collapser meta :meta)))\n      (is (= \"collapse\" ((:collapse-fn hm) nil)))\n      (is (= \"map\" ((:map-fn hm) nil nil))))))\n\n; This is a version of the larger batcher example above using macros\n(defcommand to-upper-batcher\n  \"a batch version of to-upper\"\n  [xs]\n  (mapv #(.toUpperCase ^String %) xs))\n\n(defcollapser to-upper-collapser\n  \"A collapser that dispatches to to-upper-batcher\"\n  (collapse [arg-lists]\n    (instantiate #'to-upper-batcher (mapv first arg-lists)))\n  (map [arg-lists uppered]\n    uppered))\n\n(deftest test-defd-collapser\n  (testing \"that it actually works\"\n    (let [single-call      (to-upper-collapser \"v\") ; just to make sure collapser works as a fn\n          n 100\n          inputs           (mapv #(str \"xyx\" %) (range n))\n          expected-results (to-upper-batcher inputs)\n          to-upper         (partial queue #'to-upper-collapser)\n          queued           (doall (map (fn [x]\n                                         (Thread/sleep 1)\n                                         (to-upper x))\n                                       inputs))\n          results          (doall (map deref queued))]\n      (is (= \"V\" single-call))\n      (is (= n (count expected-results) (count results)))\n      (is (= expected-results results)))))\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/README.md",
    "content": "# hystrix-codahale-metrics-publisher\n\nThis is an implementation of [HystrixMetricsPublisher](http://netflix.github.com/Hystrix/javadoc/index.html?com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisher.html) that publishes metrics using [Coda Hale Metrics](http://metrics.codahale.com) version 3. If you are using Yammer Metrics version 2, please use the [hystrix-yammer-metrics-publisher](../hystrix-yammer-metrics-publisher) module instead.\n\nSee the [Metrics & Monitoring](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring) Wiki for more information.\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-codahale-metrics-publisher%22).\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-codahale-metrics-publisher</artifactId>\n    <version>1.1.2</version>\n</dependency>\n```\n\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-codahale-metrics-publisher\" rev=\"1.1.2\" />\n```\n\nExample usage (make it work/plug it in):\n\n      HystrixPlugins.getInstance().registerMetricsPublisher(new HystrixCodahaleMetricsPublisher(yourMetricRegistry));\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n    api 'io.dropwizard.metrics:metrics-core:3.2.2'\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation 'org.mockito:mockito-all:1.9.5'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/codahalemetricspublisher/ConfigurableCodaHaleMetricFilter.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.Metric;\nimport com.codahale.metrics.MetricFilter;\nimport com.netflix.config.DynamicPropertyFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An implementation of @MetricFilter based upon an Archaius DynamicPropertyFactory\n *\n * To enable this filter, the property 'filter.graphite.metrics' must be set to TRUE\n *\n * If this is the case, metrics will be filtered unless METRIC_NAME = true is set in\n * the properties\n *\n *\n *  eg HystrixCommand.IndiciaService.GetIndicia.countFailure = true\n *\n *\n * For detail on how the metric names are constructed, refer to the source of the\n *\n * {@link HystrixCodaHaleMetricsPublisherCommand}\n *\n * and\n *\n * {@link HystrixCodaHaleMetricsPublisherThreadPool}\n *\n * classes.\n *\n *  @author Simon Irving\n */\npublic class ConfigurableCodaHaleMetricFilter implements MetricFilter{\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurableCodaHaleMetricFilter.class);\n\n    private DynamicPropertyFactory archaiusPropertyFactory;\n\n\n    public ConfigurableCodaHaleMetricFilter(DynamicPropertyFactory archaiusPropertyFactory)\n    {\n        this.archaiusPropertyFactory = archaiusPropertyFactory;\n    }\n\n    @Override\n    public boolean matches(String s, Metric metric) {\n\n        if (!isFilterEnabled())\n        {\n            return true;\n        }\n\n        boolean matchesFilter = archaiusPropertyFactory.getBooleanProperty(s, false).get();\n\n        LOGGER.debug(\"Does metric [{}] match filter? [{}]\",s,matchesFilter);\n\n        return matchesFilter;\n    }\n\n    protected boolean isFilterEnabled() {\n\n        boolean filterEnabled = archaiusPropertyFactory.getBooleanProperty(\"filter.graphite.metrics\", false).get();\n\n        LOGGER.debug(\"Is filter enabled? [{}]\", filterEnabled);\n\n        return filterEnabled;\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/codahalemetricspublisher/HystrixCodaHaleMetricsPublisher.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.MetricRegistry;\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\n\n/**\n * Coda Hale Metrics (https://github.com/codahale/metrics) implementation of {@link HystrixMetricsPublisher}.\n */\npublic class HystrixCodaHaleMetricsPublisher extends HystrixMetricsPublisher {\n    private final String metricsRootNode;\n    private final MetricRegistry metricRegistry;\n\n    public HystrixCodaHaleMetricsPublisher(MetricRegistry metricRegistry) {\n        this(null, metricRegistry);\n    }\n\n    public HystrixCodaHaleMetricsPublisher(String metricsRootNode, MetricRegistry metricRegistry) {\n        this.metricsRootNode = metricsRootNode;\n        this.metricRegistry = metricRegistry;\n    }\n\n    @Override\n    public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        return new HystrixCodaHaleMetricsPublisherCommand(metricsRootNode, commandKey, commandGroupKey, metrics, circuitBreaker, properties, metricRegistry);\n    }\n\n    @Override\n    public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        return new HystrixCodaHaleMetricsPublisherThreadPool(metricsRootNode, threadPoolKey, metrics, properties, metricRegistry);\n    }\n\n    @Override\n    public HystrixMetricsPublisherCollapser getMetricsPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        return new HystrixCodaHaleMetricsPublisherCollapser(collapserKey, metrics, properties, metricRegistry);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/codahalemetricspublisher/HystrixCodaHaleMetricsPublisherCollapser.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.Gauge;\nimport com.codahale.metrics.MetricRegistry;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherCollapser} using Coda Hale Metrics (https://github.com/codahale/metrics)\n */\npublic class HystrixCodaHaleMetricsPublisherCollapser implements HystrixMetricsPublisherCollapser {\n    private final HystrixCollapserKey key;\n    private final HystrixCollapserMetrics metrics;\n    private final HystrixCollapserProperties properties;\n    private final MetricRegistry metricRegistry;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixCodaHaleMetricsPublisherCollapser.class);\n\n    public HystrixCodaHaleMetricsPublisherCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties, MetricRegistry metricRegistry) {\n        this.key = collapserKey;\n        this.metrics = metrics;\n        this.properties = properties;\n        this.metricRegistry = metricRegistry;\n        this.metricType = key.name();\n    }\n\n    /**\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-codahale-metrics-publisher,\n     * the code below may reference a HystrixRollingNumberEvent that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     */\n    @Override\n    public void initialize() {\n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricRegistry.register(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        // cumulative counts\n        safelyCreateCumulativeCountForEvent(\"countRequestsBatched\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_REQUEST_BATCHED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countBatches\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_BATCH;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n\n        // rolling counts\n        safelyCreateRollingCountForEvent(\"rollingRequestsBatched\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_REQUEST_BATCHED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingBatches\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_BATCH;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n\n        // batch size metrics\n        metricRegistry.register(createMetricName(\"batchSize_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizeMean();\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(25);\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(50);\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(75);\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(90);\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(99);\n            }\n        });\n        metricRegistry.register(createMetricName(\"batchSize_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getBatchSizePercentile(99.5);\n            }\n        });\n\n        // shard size metrics\n        metricRegistry.register(createMetricName(\"shardSize_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizeMean();\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(25);\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(50);\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(75);\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(90);\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(99);\n            }\n        });\n        metricRegistry.register(createMetricName(\"shardSize_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getShardSizePercentile(99.5);\n            }\n        });\n\n        // properties (so the values can be inspected and monitored)\n        metricRegistry.register(createMetricName(\"propertyValue_rollingStatisticalWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_requestCacheEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_maxRequestsInBatch\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.maxRequestsInBatch().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_timerDelayInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.timerDelayInMilliseconds().get();\n            }\n        });\n    }\n\n    protected String createMetricName(String name) {\n        return MetricRegistry.name(\"\", metricType, name);\n    }\n\n    protected void createCumulativeCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return metrics.getCumulativeCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateCumulativeCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getCumulativeCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing CodaHale metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n\n    protected void createRollingCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return metrics.getRollingCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateRollingCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getRollingCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing CodaHale metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/codahalemetricspublisher/HystrixCodaHaleMetricsPublisherCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.Gauge;\nimport com.codahale.metrics.MetricRegistry;\nimport com.netflix.hystrix.*;\nimport com.netflix.hystrix.metric.consumer.*;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherCommand} using Coda Hale Metrics (https://github.com/codahale/metrics)\n */\npublic class HystrixCodaHaleMetricsPublisherCommand implements HystrixMetricsPublisherCommand {\n    private final String metricsRootNode;\n    private final HystrixCommandKey key;\n    private final HystrixCommandGroupKey commandGroupKey;\n    private final HystrixCommandMetrics metrics;\n    private final HystrixCircuitBreaker circuitBreaker;\n    private final HystrixCommandProperties properties;\n    private final MetricRegistry metricRegistry;\n    private final String metricGroup;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixCodaHaleMetricsPublisherCommand.class);\n\n    public HystrixCodaHaleMetricsPublisherCommand(String metricsRootNode, HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties, MetricRegistry metricRegistry) {\n        this.metricsRootNode = metricsRootNode;\n        this.key = commandKey;\n        this.commandGroupKey = commandGroupKey;\n        this.metrics = metrics;\n        this.circuitBreaker = circuitBreaker;\n        this.properties = properties;\n        this.metricRegistry = metricRegistry;\n        this.metricGroup = commandGroupKey.name();\n        this.metricType = key.name();\n    }\n\n    /**\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-codahale-metrics-publisher,\n     * the code below may reference a HystrixRollingNumberEvent that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     */\n    @Override\n    public void initialize() {\n        metricRegistry.register(createMetricName(\"isCircuitBreakerOpen\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return circuitBreaker.isOpen();\n            }\n        });\n\n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricRegistry.register(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        // cumulative counts\n        safelyCreateCumulativeCountForEvent(\"countBadRequests\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.BAD_REQUEST;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countCollapsedRequests\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countEmit\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.EMIT;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countExceptionsThrown\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.EXCEPTION_THROWN;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFailure\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FAILURE;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackEmit\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_EMIT;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackFailure\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_FAILURE;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackDisabled\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_DISABLED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackMissing\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_MISSING;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackRejection\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_REJECTION;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countFallbackSuccess\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_SUCCESS;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countSemaphoreRejected\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SEMAPHORE_REJECTED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countShortCircuited\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SHORT_CIRCUITED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countSuccess\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SUCCESS;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countThreadPoolRejected\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.THREAD_POOL_REJECTED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countTimeout\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.TIMEOUT;\n            }\n        });\n\n        // rolling counts\n        safelyCreateRollingCountForEvent(\"rollingCountBadRequests\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.BAD_REQUEST;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountCollapsedRequests\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountEmit\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.EMIT;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountExceptionsThrown\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.EXCEPTION_THROWN;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFailure\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FAILURE;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackEmit\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_EMIT;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackFailure\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_FAILURE;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackDisabled\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_DISABLED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackMissing\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_MISSING;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackRejection\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_REJECTION;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountFallbackSuccess\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.FALLBACK_SUCCESS;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountSemaphoreRejected\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SEMAPHORE_REJECTED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountShortCircuited\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SHORT_CIRCUITED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountSuccess\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.SUCCESS;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountThreadPoolRejected\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.THREAD_POOL_REJECTED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountTimeout\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.TIMEOUT;\n            }\n        });\n        // the rolling number of MaxConcurrentExecutionCount. Can be used to determine saturation\n        safelyCreateRollingCountForEvent(\"rollingMaxConcurrentExecutionCount\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE;\n            }\n        });\n\n        // the number of executionSemaphorePermits in use right now\n        metricRegistry.register(createMetricName(\"executionSemaphorePermitsInUse\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getCurrentConcurrentExecutionCount();\n            }\n        });\n\n        // error percentage derived from current metrics\n        metricRegistry.register(createMetricName(\"errorPercentage\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getHealthCounts().getErrorPercentage();\n            }\n        });\n\n        // latency metrics\n        metricRegistry.register(createMetricName(\"latencyExecute_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimeMean();\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_5\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(5);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(25);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(50);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(75);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(90);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(99);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyExecute_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getExecutionTimePercentile(99.5);\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"latencyTotal_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimeMean();\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_5\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(5);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(25);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(50);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(75);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(90);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(99);\n            }\n        });\n        metricRegistry.register(createMetricName(\"latencyTotal_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer getValue() {\n                return metrics.getTotalTimePercentile(99.5);\n            }\n        });\n\n        // group\n        metricRegistry.register(createMetricName(\"commandGroup\"), new Gauge<String>() {\n            @Override\n            public String getValue() {\n                return commandGroupKey != null ? commandGroupKey.name() : null;\n            }\n        });\n\n        // properties (so the values can be inspected and monitored)\n        metricRegistry.register(createMetricName(\"propertyValue_rollingStatisticalWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_circuitBreakerRequestVolumeThreshold\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerRequestVolumeThreshold().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_circuitBreakerSleepWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerSleepWindowInMilliseconds().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_circuitBreakerErrorThresholdPercentage\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerErrorThresholdPercentage().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_circuitBreakerForceOpen\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.circuitBreakerForceOpen().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_circuitBreakerForceClosed\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.circuitBreakerForceClosed().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_executionTimeoutInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_executionIsolationStrategy\"), new Gauge<String>() {\n            @Override\n            public String getValue() {\n                return properties.executionIsolationStrategy().get().name();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_metricsRollingPercentileEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.metricsRollingPercentileEnabled().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_requestCacheEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_requestLogEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean getValue() {\n                return properties.requestLogEnabled().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.executionIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n        metricRegistry.register(createMetricName(\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.fallbackIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n\n        RollingCommandEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        CumulativeCommandEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandLatencyDistributionStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandUserLatencyDistributionStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandMaxConcurrencyStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n    }\n\n    protected String createMetricName(String name) {\n        return MetricRegistry.name(metricsRootNode, metricGroup, metricType, name);\n    }\n\n    protected void createCumulativeCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return metrics.getCumulativeCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateCumulativeCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getCumulativeCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing CodaHale metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n\n    protected void createRollingCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return metrics.getRollingCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateRollingCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricRegistry.register(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getRollingCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing CodaHale metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/codahalemetricspublisher/HystrixCodaHaleMetricsPublisherThreadPool.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.Gauge;\nimport com.codahale.metrics.MetricRegistry;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherThreadPool} using Coda Hale Metrics (https://github.com/codahale/metrics)\n */\npublic class HystrixCodaHaleMetricsPublisherThreadPool implements HystrixMetricsPublisherThreadPool {\n    private final String metricsRootNode;\n    private final HystrixThreadPoolKey key;\n    private final HystrixThreadPoolMetrics metrics;\n    private final HystrixThreadPoolProperties properties;\n    private final MetricRegistry metricRegistry;\n    private final String metricGroup;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixCodaHaleMetricsPublisherThreadPool.class);\n\n    public HystrixCodaHaleMetricsPublisherThreadPool(String metricsRootNode, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties, MetricRegistry metricRegistry) {\n        this.metricsRootNode = metricsRootNode;\n        this.key = threadPoolKey;\n        this.metrics = metrics;\n        this.properties = properties;\n        this.metricRegistry = metricRegistry;\n        this.metricGroup = \"HystrixThreadPool\";\n        this.metricType = key.name();\n    }\n\n    /**\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-codahale-metrics-publisher,\n     * the code below may reference a HystrixRollingNumberEvent that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     */\n    @Override\n    public void initialize() {\n        metricRegistry.register(createMetricName(\"name\"), new Gauge<String>() {\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n        });\n\n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricRegistry.register(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long getValue() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"threadActiveCount\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentActiveCount();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"completedTaskCount\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentCompletedTaskCount();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"largestPoolSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentLargestPoolSize();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"totalTaskCount\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentTaskCount();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"queueSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentQueueSize();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"rollingMaxActiveThreads\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getRollingMaxActiveThreads();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"countThreadsExecuted\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getCumulativeCountThreadsExecuted();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"rollingCountCommandsRejected\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                try {\n                    return metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED);\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing CodaHale metrics, error looking up eventType for : rollingCountCommandsRejected.  Please check that all Hystrix versions are the same!\");\n                    return 0L;\n                }\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"rollingCountThreadsExecuted\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return metrics.getRollingCountThreadsExecuted();\n            }\n        });\n\n        // properties\n        metricRegistry.register(createMetricName(\"propertyValue_corePoolSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.coreSize().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_maximumSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.maximumSize().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_actualMaximumSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.actualMaximumSize();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_keepAliveTimeInMinutes\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.keepAliveTimeMinutes().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_queueSizeRejectionThreshold\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.queueSizeRejectionThreshold().get();\n            }\n        });\n\n        metricRegistry.register(createMetricName(\"propertyValue_maxQueueSize\"), new Gauge<Number>() {\n            @Override\n            public Number getValue() {\n                return properties.maxQueueSize().get();\n            }\n        });\n    }\n\n    protected String createMetricName(String name) {\n        return MetricRegistry.name(metricsRootNode, metricGroup, metricType, name);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/test/java/com/netflix/hystrix/contrib/codahalemetricspublisher/ConfigurableCodaHaleMetricFilterTest.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.Metric;\nimport com.netflix.config.DynamicBooleanProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport org.junit.After;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verifyZeroInteractions;\nimport static org.mockito.Mockito.when;\n\n/**\n * Test the ConfigurableCodaHaleMetricFilter\n *\n * @author Simon Irving\n */\npublic class ConfigurableCodaHaleMetricFilterTest {\n\n    private Metric metric = mock(Metric.class);\n\n    private final static DynamicPropertyFactory archiausPropertyFactory = mock(DynamicPropertyFactory.class);\n\n    private static final DynamicBooleanProperty DYNAMIC_BOOLEAN_TRUE = mock(DynamicBooleanProperty.class);\n    private static final DynamicBooleanProperty DYNAMIC_BOOLEAN_FALSE = mock(DynamicBooleanProperty.class);\n\n    @BeforeClass\n    public static void initialiseMocks()\n    {\n        when(archiausPropertyFactory.getBooleanProperty(any(String.class), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_FALSE);\n        when(archiausPropertyFactory.getBooleanProperty(eq(\"this.metric.is.allowed\"), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_TRUE);\n        when(DYNAMIC_BOOLEAN_TRUE.get()).thenReturn(true);\n        when(DYNAMIC_BOOLEAN_FALSE.get()).thenReturn(false);\n    }\n\n    @After\n    public void assertMetricsNotTouched()\n    {\n        verifyZeroInteractions(metric);\n    }\n\n    @Test\n    public void testMetricConfiguredInFilterWithFilterEnabled()\n    {\n        when(archiausPropertyFactory.getBooleanProperty(eq(\"filter.graphite.metrics\"), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_TRUE);\n        ConfigurableCodaHaleMetricFilter filter = new ConfigurableCodaHaleMetricFilter(archiausPropertyFactory);\n        assertTrue(filter.matches(\"this.metric.is.allowed\", metric));\n    }\n\n    @Test\n    public void testMetricConfiguredInFilterWithFilterDisabled()\n    {\n        when(archiausPropertyFactory.getBooleanProperty(eq(\"filter.graphite.metrics\"), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_FALSE);\n        ConfigurableCodaHaleMetricFilter filter = new ConfigurableCodaHaleMetricFilter(archiausPropertyFactory);\n        assertTrue(filter.matches(\"this.metric.is.allowed\", metric));\n    }\n\n    @Test\n    public void testMetricNotConfiguredInFilterWithFilterEnabled()\n    {\n        when(archiausPropertyFactory.getBooleanProperty(eq(\"filter.graphite.metrics\"), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_TRUE);\n        ConfigurableCodaHaleMetricFilter filter = new ConfigurableCodaHaleMetricFilter(archiausPropertyFactory);\n        assertFalse(filter.matches(\"this.metric.is.not.allowed\", metric));\n    }\n\n    @Test\n    public void testMetricNotConfiguredInFilterWithFilterDisabled()\n    {\n        when(archiausPropertyFactory.getBooleanProperty(eq(\"filter.graphite.metrics\"), any(Boolean.class))).thenReturn(DYNAMIC_BOOLEAN_FALSE);\n        ConfigurableCodaHaleMetricFilter filter = new ConfigurableCodaHaleMetricFilter(archiausPropertyFactory);\n        assertTrue(filter.matches(\"this.metric.is.not.allowed\", metric));\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-codahale-metrics-publisher/src/test/java/com/netflix/hystrix/contrib/codahalemetricspublisher/HystrixCodaHaleMetricsPublisherCommandTest.java",
    "content": "package com.netflix.hystrix.contrib.codahalemetricspublisher;\n\nimport com.codahale.metrics.MetricRegistry;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.core.Is.is;\nimport static org.junit.Assert.assertThat;\n\npublic class HystrixCodaHaleMetricsPublisherCommandTest {\n    private final MetricRegistry metricRegistry = new MetricRegistry();\n\n    @Before\n    public void setup() {\n        HystrixPlugins.getInstance().registerMetricsPublisher(new HystrixCodaHaleMetricsPublisher(\"hystrix\", metricRegistry));\n    }\n\n    @Test\n    public void testCommandSuccess() throws InterruptedException {\n        Command command = new Command();\n        command.execute();\n\n        Thread.sleep(1000);\n\n        assertThat((Long) metricRegistry.getGauges().get(\"hystrix.testGroup.testCommand.countSuccess\").getValue(), is(1L));\n        assertThat((Long) metricRegistry.getGauges().get(\"hystrix.HystrixThreadPool.threadGroup.totalTaskCount\").getValue(), is(1L));\n\n    }\n\n    private static class Command extends HystrixCommand<Void> {\n        final static HystrixCommandKey hystrixCommandKey = HystrixCommandKey.Factory.asKey(\"testCommand\");\n        final static HystrixCommandGroupKey hystrixCommandGroupKey = HystrixCommandGroupKey.Factory.asKey(\"testGroup\");\n        final static HystrixThreadPoolKey hystrixThreadPool = HystrixThreadPoolKey.Factory.asKey(\"threadGroup\");\n\n        Command() {\n            super(Setter.withGroupKey(hystrixCommandGroupKey).andCommandKey(hystrixCommandKey).andThreadPoolKey(hystrixThreadPool));\n        }\n\n        @Override\n        protected Void run() throws Exception {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/README.md",
    "content": "# hystrix-javanica\n\nJava language has a great advantages over other languages such as reflection and annotations.\nAll modern frameworks such as Spring, Hibernate, myBatis and etc. seek to use this advantages to the maximum.\nThe idea of introduction annotations in Hystrix is obvious solution for improvement. Currently using Hystrix involves writing a lot of code that is a barrier to rapid development. You likely be spending a lot of time on writing a Hystrix commands. Idea of the Javanica project is make easier using of Hystrix by the introduction of support annotations.\n\nFirst of all in order to use hystrix-javanica you need to add hystrix-javanica dependency in your project.\n\nExample for Maven:\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-javanica</artifactId>\n    <version>x.y.z</version>\n</dependency>\n```\n\nTo implement AOP functionality in the project was used AspectJ library. If in your project already used AspectJ then you need to add hystrix aspect in aop.xml as below:\n```xml\n<aspects>\n        ...\n        <aspect name=\"com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect\"/>\n        ...\n</aspects>\n```\nMore about AspectJ configuration read [here] (http://www.eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html)\n\n\nIf you use Spring AOP in your project then you need to add specific configuration using Spring AOP namespace in order to make Spring capable to manage aspects which were written using AspectJ and declare `HystrixCommandAspect` as Spring bean like below:\n\n```xml\n    <aop:aspectj-autoproxy/>\n    <bean id=\"hystrixAspect\" class=\"com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect\"></bean>\n```\n\nOr if you are using Spring code configuration:\n\n```java\n@Configuration\npublic class HystrixConfiguration {\n\n  @Bean\n  public HystrixCommandAspect hystrixAspect() {\n    return new HystrixCommandAspect();\n  }\n\n}\n```\n\nIt doesn't matter which approach you use to create proxies in Spring, javanica works fine with JDK and CGLIB proxies. If you use another framework for aop which supports AspectJ and uses other libs (Javassist for instance) to create proxies then let us know what lib you use to create proxies and we'll try to add support for this library in near future.\n\nMore about Spring AOP + AspectJ read [here] (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html)\n\n## Aspect weaving\nJavanica supports two weaving modes: implementation and runtime. Load time weaving hasn't been tested but it should work. If you tried LTW mode and got any problems then raise javanica issue or create pull request with fix.\n- CTW. To use CTW mode you need to use specific jar version: **hystrix-javanica-ctw-X.Y.Z** . This jar is assembled with aspects compiled with using [AJC](https://eclipse.org/aspectj/doc/next/devguide/ajc-ref.html) compiler. If you will try to use regular hystrix-javanica-X.Y.Z with CTW then you get ``` NoSuchMethodError aspectOf() ``` at runtime from building with iajc. Also, you need to start your app with using java property: ```-DWeavingMode=compile```.\n**NOTE**: Javanica depends on aspectj library and uses internal features of aspectj and these features aren't provided as a part of open API thus it can change from version to version. Javanica tested with latest aspectj version 1.8.7. If you updated aspectj version and noticed any issues then please don't hestitate to create new issue or contribute.\n- RTW works, you can use regular hystrix-javanica-X.Y.Z\n- LTM hasn't been tested but it should work fine.\n\n\n# How to use\n\n## Hystrix command\n### Synchronous Execution\n\nTo run method as Hystrix command synchronously you need to annotate method with `@HystrixCommand` annotation, for example\n```java\npublic class UserService {\n...\n    @HystrixCommand\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n}\n...\n```\nIn example above the `getUserById` method will be processed [synchronously](https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Synchronous-Execution) within new Hystrix command. \nBy default the name of **command key** is command method name: `getUserById`, default **group key** name is class name of annotated method: `UserService`. You can change it using necessary `@HystrixCommand` properties:\n\n```java\n    @HystrixCommand(groupKey=\"UserGroup\", commandKey = \"GetUserByIdCommand\")\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n```\nTo set threadPoolKey use ```@HystrixCommand#threadPoolKey()```\n\n### Asynchronous Execution\n\nTo process Hystrix command asynchronously you should return an instance of `AsyncResult` in your command method as in the example below:\n```java\n    @HystrixCommand\n    public Future<User> getUserByIdAsync(final String id) {\n        return new AsyncResult<User>() {\n            @Override\n            public User invoke() {\n                return userResource.getUserById(id);\n            }\n        };\n    }\n```\n\nThe return type of command method should be Future that indicates that a command should be executed [asynchronously] (https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Asynchronous-Execution).\n\n## Reactive Execution\n\nTo perform \"Reactive Execution\" you should return an instance of `Observable` in your command method as in the example below:\n\n```java\n    @HystrixCommand\n    public Observable<User> getUserById(final String id) {\n        return Observable.create(new Observable.OnSubscribe<User>() {\n                @Override\n                public void call(Subscriber<? super User> observer) {\n                    try {\n                        if (!observer.isUnsubscribed()) {\n                            observer.onNext(new User(id, name + id));\n                            observer.onCompleted();\n                        }\n                    } catch (Exception e) {\n                        observer.onError(e);\n                    }\n                }\n            });\n    }\n```\nIn addition to `Observable` Javanica supports the following RX types: `Single` and `Completable`.\nHystrix core supports only one RX type which is `Observable`, `HystrixObservableCommand` requires to return `Observable` therefore javanica transforms `Single` or `Completable` to `Observable` using `toObservable()` method for appropriate type and before returning the result to caller it translates `Observable` to either `Single` or `Completable`  using `toSingle()` or `toCompletable()` correspondingly.\n\nHystrixObservable interface provides two methods: ```observe()``` - eagerly starts execution of the command the same as ``` HystrixCommand#queue()``` and ```HystrixCommand#execute()```; ```toObservable()``` - lazily starts execution of the command only once the Observable is subscribed to. To control this behaviour and swith between two modes ```@HystrixCommand``` provides specific parameter called ```observableExecutionMode```.\n```@HystrixCommand(observableExecutionMode = EAGER)``` indicates that ```observe()``` method should be used to execute observable command\n```@HystrixCommand(observableExecutionMode = LAZY)``` indicates that ```toObservable()``` should be used to execute observable command\n\n**NOTE: EAGER mode is used by default**\n\n## Fallback\n\nGraceful degradation can be achieved by declaring name of fallback method in `@HystrixCommand` like below:\n\n```java\n    @HystrixCommand(fallbackMethod = \"defaultUser\")\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n\n    private User defaultUser(String id) {\n        return new User(\"def\", \"def\");\n    }\n```\n\n**_Its important to remember that Hystrix command and fallback should be placed in the same class and have same method signature (optional parameter for failed execution exception)_**.\n\nFallback method can have any access modifier. Method `defaultUser` will be used to process fallback logic in a case of any errors. If you need to run fallback method `defaultUser` as separate Hystrix command then you need to annotate it with `HystrixCommand` annotation as below:\n```java\n    @HystrixCommand(fallbackMethod = \"defaultUser\")\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n\n    @HystrixCommand\n    private User defaultUser(String id) {\n        return new User();\n    }\n```\n\nIf fallback method was marked with `@HystrixCommand` then this fallback method (_defaultUser_) also can has own fallback method, as in the example below:\n```java\n    @HystrixCommand(fallbackMethod = \"defaultUser\")\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n\n    @HystrixCommand(fallbackMethod = \"defaultUserSecond\")\n    private User defaultUser(String id) {\n        return new User();\n    }\n    \n    @HystrixCommand\n    private User defaultUserSecond(String id) {\n        return new User(\"def\", \"def\");\n    }\n```\n\nJavanica provides an ability to get execution exception (exception thrown that caused the failure of a command) within a fallback is being executed. A fallback method signature can be extended with an additional parameter in order to get an exception thrown by a command. Javanica exposes execution exception through additional parameter of fallback method. Execution exception is derived by calling method getExecutionException() as in vanilla hystrix.\n\nExample:\n\n```java\n        @HystrixCommand(fallbackMethod = \"fallback1\")\n        User getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback2\")\n        User fallback1(String id, Throwable e) {\n            assert \"getUserById command failed\".equals(e.getMessage());\n            throw new RuntimeException(\"fallback1 failed\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback3\")\n        User fallback2(String id) {\n            throw new RuntimeException(\"fallback2 failed\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"staticFallback\")\n        User fallback3(String id, Throwable e) {\n            assert \"fallback2 failed\".equals(e.getMessage());\n            throw new RuntimeException(\"fallback3 failed\");\n        }\n\n        User staticFallback(String id, Throwable e) {\n            assert \"fallback3 failed\".equals(e.getMessage());\n            return new User(\"def\", \"def\");\n        }\n        \n        // test\n        @Test\n        public void test() {\n        assertEquals(\"def\", getUserById(\"1\").getName());\n        }\n```\nAs you can see, the additional ```Throwable``` parameter is not mandatory and can be omitted or specified.\nA fallback gets an exception thrown that caused a failure of parent, thus the ```fallback3``` gets exception thrown by ```fallback2```, no by ```getUserById``` command.\n\n### Async/Sync fallback.\nA fallback can be async or sync, at certain cases it depends on command execution type, below listed all possible uses :\n\n**Supported**\n\ncase 1: sync command, sync fallback\n\n```java\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        User getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        @HystrixCommand\n        User fallback(String id) {\n            return new User(\"def\", \"def\");\n        }\n```\n\ncase 2: async command, sync fallback\n\n```java\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        Future<User> getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        @HystrixCommand\n        User fallback(String id) {\n            return new User(\"def\", \"def\");\n        }\n```\n\ncase 3: async command, async fallback\n```java\n        @HystrixCommand(fallbackMethod = \"fallbackAsync\")\n        Future<User> getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        @HystrixCommand\n        Future<User> fallbackAsync(String id) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(\"def\", \"def\");\n                }\n            };\n        }\n```\n\n**Unsupported(prohibited)**\n\ncase 1: sync command, async fallback command. This case isn't supported because in the essence a caller does not get a future buy calling ```getUserById``` and future is provided by fallback isn't available for a caller anyway, thus execution of a command forces to complete ```fallbackAsync``` before a caller gets a result, having said it turns out there is no benefits of async fallback execution. But it can be convenient if a fallback is used for both sync and async commands, if you see this case is very helpful and will be nice to have then create issue to add support for this case.\n\n```java\n        @HystrixCommand(fallbackMethod = \"fallbackAsync\")\n        User getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        @HystrixCommand\n        Future<User> fallbackAsync(String id) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(\"def\", \"def\");\n                }\n            };\n        }\n```\ncase 2: sync command, async fallback. This case isn't supported for the same reason as for the case 1.\n\n```java\n        @HystrixCommand(fallbackMethod = \"fallbackAsync\")\n        User getUserById(String id) {\n            throw new RuntimeException(\"getUserById command failed\");\n        }\n\n        Future<User> fallbackAsync(String id) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(\"def\", \"def\");\n                }\n            };\n        }\n```\n\nSame restrictions are imposed on using observable feature in javanica.\n\n## Default fallback for class or concrete command\nThis feature allows to define default fallback for the whole class or concrete command. If you have a batch of commands with exactly the same fallback logic you still have to define a fallback method for every command because fallback method should have exactly the same signature as command does, consider the following code:\n\n```java\n    public class Service {\n        @RequestMapping(value = \"/test1\")\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public APIResponse test1(String param1) {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        @RequestMapping(value = \"/test2\")\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public APIResponse test2() {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        @RequestMapping(value = \"/test3\")\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public APIResponse test3(ObjectRequest obj) {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        private APIResponse fallback(String param1) {\n            return APIResponse.failed(\"Server is busy\");\n        }\n\n        private APIResponse fallback() {\n            return APIResponse.failed(\"Server is busy\");\n        }\n        \n        private APIResponse fallback(ObjectRequest obj) {\n            return APIResponse.failed(\"Server is busy\");\n        }\n    }\n```\n\nDefault fallback feature allows to engage DRY principle and get rid of redundancy:\n\n```java\n    @DefaultProperties(defaultFallback = \"fallback\")\n    public class Service {\n        @RequestMapping(value = \"/test1\")\n        @HystrixCommand\n        public APIResponse test1(String param1) {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        @RequestMapping(value = \"/test2\")\n        @HystrixCommand\n        public APIResponse test2() {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        @RequestMapping(value = \"/test3\")\n        @HystrixCommand\n        public APIResponse test3(ObjectRequest obj) {\n            // some codes here\n            return APIResponse.success(\"success\");\n        }\n\n        private APIResponse fallback() {\n            return APIResponse.failed(\"Server is busy\");\n        }\n    }\n```\n\nDefault fallback method should not have any parameters except extra one to get execution exception and shouldn't throw any exceptions.\nBelow fallbacks listed in descending order of priority:\n\n1. command fallback defined using `fallbackMethod` property of `@HystrixCommand`\n2. command default fallback defined using `defaultFallback` property of `@HystrixCommand`\n3. class default fallback defined using `defaultFallback` property of `@DefaultProperties`\n\n\n## Error Propagation\nBased on [this](https://github.com/Netflix/Hystrix/wiki/How-To-Use#ErrorPropagation) description, `@HystrixCommand` has an ability to specify exceptions types which should be ignored.\n\n```java\n    @HystrixCommand(ignoreExceptions = {BadRequestException.class})\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n```\n\nIf `userResource.getUserById(id);` throws an exception that type is _BadRequestException_ then this exception will be wrapped in ``HystrixBadRequestException`` and re-thrown without triggering fallback logic. You don't need to do it manually, javanica will do it for you under the hood.\n\nIt is worth noting that by default a caller will always get the root cause exception e.g. ``BadRequestException``, never ``HystrixBadRequestException`` or ``HystrixRuntimeException`` (except the case when executed code explicitly throws those exceptions).\n\nOptionally this exception un-wrapping can be disabled for ``HystrixRuntimeException`` by using ``raiseHystrixExceptions`` i.e. all exceptions that are not ignored are raised as the _cause_ of a ``HystrixRuntimeException``:\n\n```java\n    @HystrixCommand(\n        ignoreExceptions = {BadRequestException.class},\n        raiseHystrixExceptions = {HystrixException.RUNTIME_EXCEPTION})\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n```\n\n*Note*: If command has a fallback then only first exception that triggers fallback logic will be propagated to caller. Example:\n\n```java\nclass Service {\n    @HystrixCommand(fallbackMethod = \"fallback\")\n    Object command(Object o) throws CommandException {\n        throw new CommandException();\n    }\n    \n    @HystrixCommand\n    Object fallback(Object o) throws FallbackException {\n        throw new FallbackException();\n    }\n}\n\n// in client code\n{\n    try {\n        service.command(null);\n    } catch (Exception e) {\n      assert CommandException.class.equals(e.getClass())\n    }\n}\n```\n\n## Request Cache\n\nJavanica provides specific annotations in order to enable and manage request caching. This annotations look very similar to [JSR107](https://github.com/jsr107/jsr107spec) but less extensive than those, by other hand Hystrix doesn't provide independent and complex caching system therefore  there is no need to have such diversity of annotations as in JSR107.\nJavanica has only three annotations dedicated for request caching.\n\n\n| Annotation        | Description           | Properties  |\n| ------------- |-------------| -----|\n| @CacheResult     | Marks a methods that results should be cached for a Hystrix command.This annotation must be used in conjunction with HystrixCommand annotation. | cacheKeyMethod |\n| @CacheRemove     | Marks methods used to invalidate cache of a command. Generated cache key must be same as key generated within link CacheResult context      |   commandKey, cacheKeyMethod |\n| @CacheKey | Marks a method argument as part of the cache key. If no arguments are marked all arguments are used. If _@CacheResult_ or _@CacheRemove_ annotation has specified _cacheKeyMethod_ then a method arguments will not be used to build cache key even if they annotated with _@CacheKey_    |    value |\n\n**cacheKeyMethod** - a method name to be used to get a key for request caching. The command and cache key method should be placed in the same class and have same method signature except cache key method return type that should be _String_.\n_cacheKeyMethod_ has higher priority than an arguments of a method, that means what actual arguments\nof a method that annotated with _@CacheResult_ will not be used to generate cache key, instead specified\n_cacheKeyMethod_ fully assigns to itself responsibility for cache key generation.\nBy default this returns empty string which means \"do not use cache method.\nYou can consider _cacheKeyMethod_ as a replacement for common key generators (for example [JSR170-CacheKeyGenerator](https://github.com/jsr107/jsr107spec/blob/master/src/main/java/javax/cache/annotation/CacheKeyGenerator.java)) but with _cacheKeyMethod_ cache key generation becomes more convenient and simple. Not to be unfounded let's compare the two approaches:\nJSR107\n```java\n\n    @CacheRemove(cacheName = \"getUserById\", cacheKeyGenerator = UserCacheKeyGenerator.class)\n    @HystrixCommand\n    public void update(@CacheKey User user) {\n         storage.put(user.getId(), user);\n    }\n        \n    public static class UserCacheKeyGenerator implements HystrixCacheKeyGenerator {\n        @Override\n        public HystrixGeneratedCacheKey generateCacheKey(CacheKeyInvocationContext<? extends Annotation>  cacheKeyInvocationContext) {\n            CacheInvocationParameter cacheInvocationParameter = cacheKeyInvocationContext.getKeyParameters()[0];\n            User user = (User) cacheInvocationParameter.getValue();\n            return new DefaultHystrixGeneratedCacheKey(user.getId());\n        }\n    }\n```\n\nJavanica cacheKeyMethod\n\n```java\n        @CacheRemove(commandKey = \"getUserById\", cacheKeyMethod=)\n        @HystrixCommand\n        public void update(User user) {\n            storage.put(user.getId(), user);\n        }\n        private String cacheKeyMethod(User user) {\n            return user.getId();\n        }\n\n```\nor even just\n```java\n        @CacheRemove(commandKey = \"getUserById\")\n        @HystrixCommand\n        public void update(@CacheKey(\"id\") User user) {\n            storage.put(user.getId(), user);\n        }\n```\nYou don't need to create new classes, also approach with cacheKeyMethod helps during refactoring if you will give correct names for cache key methods. It is recommended to append prefix \"cacheKeyMethod\" to the real method name, for example:\n```java\npublic User getUserById(@CacheKey String id);\n```\n```java\nprivate User getUserByIdCacheKeyMethod(String id);\n```\n**Cache key generator**\n\nJavanica has only one cache key generator **HystrixCacheKeyGenerator** that generates a _HystrixGeneratedCacheKey_ based on _CacheInvocationContext_. Implementation is thread-safe.\nParameters of an annotated method are selected by the following rules:\n- If no parameters are annotated with _@CacheKey_ then all parameters are included\n- If one or more _@CacheKey_ annotations exist only those parameters with the _@CacheKey_ annotation are included\n\n**Note**:  If _CacheResult_ or _CacheRemove_ annotation has specified **cacheKeyMethod** then a method arguments **will not be used to build cache key** even if they annotated with _CacheKey_.\n\n**@CacheKey and value property**\nThis annotation has one property by default that allows specify name of a certain argument property. for example: ```@CacheKey(\"id\") User user```, or in case composite property: ```@CacheKey(\"profile.name\") User user```. Null properties are ignored, i.e. if ```profile``` is ```null```  then result of ```@CacheKey(\"profile.name\") User user``` will be empty string.\n\nExamples:\n\n```java\n        @CacheResult\n        @HystrixCommand\n        public User getUserById(@CacheKey String id) {\n            return storage.get(id);\n        }\n        \n        // --------------------------------------------------\n        @CacheResult(cacheKeyMethod = \"getUserByNameCacheKey\")\n        @HystrixCommand\n        public User getUserByName(String name) {\n            return storage.getByName(name);\n        }\n        private Long getUserByNameCacheKey(String name) {\n            return name;\n        }\n        // --------------------------------------------------\n        @CacheResult\n        @HystrixCommand\n        public void getUserByProfileName(@CacheKey(\"profile.email\") User user) {\n            storage.getUserByProfileName(user.getProfile().getName());\n        }\n        \n```\n\n**Get-Set-Get pattern**\nTo get more about this pattern you can read [this](https://github.com/Netflix/Hystrix/wiki/How-To-Use#get-set-get-with-request-cache-invalidation) chapter\nExample:\n```java\n    public class UserService {    \n        @CacheResult\n        @HystrixCommand\n        public User getUserById(@CacheKey String id) { // GET\n            return storage.get(id);\n        }\n\n        @CacheRemove(commandKey = \"getUserById\")\n        @HystrixCommand\n        public void update(@CacheKey(\"id\") User user) { // SET\n            storage.put(user.getId(), user);\n        }\n    }    \n        \n        // test app\n        \n        public void test(){\n        User user = userService.getUserById(\"1\");\n        HystrixInvokableInfo<?> getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command with\n        // the value of \"1\" so it should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the second time we've executed this command with\n        // the same value so it should return from cache\n        assertTrue(getUserByIdCommand.isResponseFromCache());\n        \n        user = new User(\"1\", \"new_name\");\n        userService.update(user); // update the user\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command after \"update\"\n        // method was invoked and a cache for \"getUserById\" command was flushed\n        // so the response shouldn't be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        }\n```\n\n**Note**: You can use @CacheRemove annotation in conjunction with  @HystrixCommand or without. If you want annotate not command method with @CacheRemove annotation then you need to add HystrixCacheAspect aspect to your configuration:\n\n```xml\n<aspects>\n        ...\n        <aspect name=\"com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect\"/>\n        ...\n</aspects>\n\n<!-- or Spring conf -->\n\n    <aop:aspectj-autoproxy/>\n    <bean id=\"hystrixAspect\" class=\"com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect\"></bean>\n\n```\n\n## Configuration\n### Command Properties\n\nCommand properties can be set using @HystrixCommand's 'commandProperties' like below:\n\n```java\n    @HystrixCommand(commandProperties = {\n            @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"500\")\n        })\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n```\n\nJavanica dynamically sets properties using Hystrix ConfigurationManager.\nFor the example above Javanica behind the scenes performs next action:\n```java\nConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.getUserById.execution.isolation.thread.timeoutInMilliseconds\", \"500\");\n```\nMore about Hystrix command properties [command](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandExecution) and [fallback](https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-CommandFallback)\n\nThreadPoolProperties can be set using @HystrixCommand's 'threadPoolProperties' like below:\n\n```java\n    @HystrixCommand(commandProperties = {\n            @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"500\")\n        },\n                threadPoolProperties = {\n                        @HystrixProperty(name = \"coreSize\", value = \"30\"),\n                        @HystrixProperty(name = \"maxQueueSize\", value = \"101\"),\n                        @HystrixProperty(name = \"keepAliveTimeMinutes\", value = \"2\"),\n                        @HystrixProperty(name = \"queueSizeRejectionThreshold\", value = \"15\"),\n                        @HystrixProperty(name = \"metrics.rollingStats.numBuckets\", value = \"12\"),\n                        @HystrixProperty(name = \"metrics.rollingStats.timeInMilliseconds\", value = \"1440\")\n        })\n    public User getUserById(String id) {\n        return userResource.getUserById(id);\n    }\n```\n\n### DefaultProperties\n``@DefaultProperties`` is class (type) level annotation that allows to default commands properties such as ``groupKey``, ``threadPoolKey``, ``commandProperties``, ``threadPoolProperties``, ``ignoreExceptions`` and ``raiseHystrixExceptions``. Properties specified using this annotation will be used by default for each hystrix command defined within annotated class unless a command specifies those properties explicitly using corresponding ``@HystrixCommand`` parameters.\nExample:\n\n```java\n@DefaultProperties(groupKey = \"DefaultGroupKey\")\nclass Service {\n    @HystrixCommand // hystrix command group key is 'DefaultGroupKey'\n    public Object commandInheritsDefaultProperties() {\n        return null;\n    }\n    @HystrixCommand(groupKey = \"SpecificGroupKey\") // command overrides default group key\n    public Object commandOverridesGroupKey() {\n        return null;\n    }\n}\n```\n\n## Hystrix collapser\n\nSuppose you have some command which calls should be collapsed in one backend call. For this goal you can use ```@HystrixCollapser``` annotation.\n\nExample:\n```java\n\n    /** Asynchronous Execution */\n    @HystrixCollapser(batchMethod = \"getUserByIds\")\n    public Future<User> getUserByIdAsync(String id) {\n        return null;\n    }\n    \n    /** Reactive Execution */\n    @HystrixCollapser(batchMethod = \"getUserByIds\")\n    public Observable<User> getUserByIdReact(String id) {\n        return null;\n    }    \n        \n    @HystrixCommand\n    public List<User> getUserByIds(List<String> ids) {\n        List<User> users = new ArrayList<User>();\n        for (String id : ids) {\n            users.add(new User(id, \"name: \" + id));\n        }\n        return users;\n    }\n\n    // Async\n    Future<User> f1 = userService.getUserByIdAsync(\"1\");\n    Future<User> f2 = userService.getUserByIdAsync(\"2\");\n    Future<User> f3 = userService.getUserByIdAsync(\"3\");\n    Future<User> f4 = userService.getUserByIdAsync(\"4\");\n    Future<User> f5 = userService.getUserByIdAsync(\"5\");\n    \n    // Reactive\n    Observable<User> u1 = getUserByIdReact(\"1\");\n    Observable<User> u2 = getUserByIdReact(\"2\");\n    Observable<User> u3 = getUserByIdReact(\"3\");\n    Observable<User> u4 = getUserByIdReact(\"4\");\n    Observable<User> u5 = getUserByIdReact(\"5\");\n    \n    // Materialize reactive commands\n    Iterable<User> users = Observables.merge(u1, u2, u3, u4, u5).toBlocking().toIterable();\n```\nA method annotated with ```@HystrixCollapser``` annotation can return any value with compatible type, it does not affect the result of collapser execution, collapser method can even return ```null``` or another stub.\nThere are several rules applied for methods signatures.\n\n1. Collapser method must have one argument of any type, desired a wrapper of a primitive type like Integer, Long, String and etc. \n2. A batch method must have one argument with type java.util.List parameterized with corresponding type, that's if a type of collapser argument is ```Integer``` then type of batch method argument must be ```List<Integer>```.\n3. Return type of batch method must be java.util.List parameterized with corresponding type, that's if a return type of collapser method is ```User``` then a return type of batch command must be ```List<User>```.\n\n**Convention for batch method behavior**\n\nThe size of response collection must be equal to the size of request collection.\n\n```java\n  @HystrixCommand\n  public List<User> getUserByIds(List<String> ids); // batch method\n  \n  List<String> ids = List(\"1\", \"2\", \"3\");\n  getUserByIds(ids).size() == ids.size();\n```\nOrder of elements in response collection must be same as in request collection.\n\n```\n @HystrixCommand\n  public List<User> getUserByIds(List<String> ids); // batch method\n  \n  List<String> ids = List(\"1\", \"2\", \"3\");\n  List<User> users = getUserByIds(ids);\n  System.out.println(users);\n  // output\n  User: id=1\n  User: id=2\n  User: id=3\n```\n\n**Why order of elements of request and response collections is important?**\n\nThe reason of this is in reducing logic, basically request elements are mapped one-to-one to response elements. Thus if order of elements of request collection is different then the result of execution can be unpredictable.\n\n**Deduplication batch command request parameters**.\n\nIn some cases your batch method can depend on behavior of third-party service or library that skips duplicates in a request. It can be a rest service that expects unique values and ignores duplicates. In this case the size of elements in request collection can be different from size of elements in response collection. It violates one of the behavior principle. To fix it you need manually map request to response, for example:\n\n```java\n// hava 8\n@HystrixCommand\nList<User> batchMethod(List<String> ids){\n// ids = [1, 2, 2, 3]\nList<User> users = restClient.getUsersByIds(ids);\n// users = [User{id='1', name='user1'}, User{id='2', name='user2'}, User{id='3', name='user3'}]\nList<User> response = ids.stream().map(it -> users.stream()\n                .filter(u -> u.getId().equals(it)).findFirst().get())\n                .collect(Collectors.toList());\n// response = [User{id='1', name='user1'}, User{id='2', name='user2'}, User{id='2', name='user2'}, User{id='3', name='user3'}]\nreturn response;\n```\n\nSame case if you want to remove duplicate elements from request collection before a service call.\nExample:\n```java\n// hava 8\n@HystrixCommand\nList<User> batchMethod(List<String> ids){\n// ids = [1, 2, 2, 3]\nList<String> uniqueIds = ids.stream().distinct().collect(Collectors.toList());\n// uniqueIds = [1, 2, 3]\nList<User> users = restClient.getUsersByIds(uniqueIds);\n// users = [User{id='1', name='user1'}, User{id='2', name='user2'}, User{id='3', name='user3'}]\nList<User> response = ids.stream().map(it -> users.stream()\n                .filter(u -> u.getId().equals(it)).findFirst().get())\n                .collect(Collectors.toList());\n// response = [User{id='1', name='user1'}, User{id='2', name='user2'}, User{id='2', name='user2'}, User{id='3', name='user3'}]\nreturn response;\n```\nTo set collapser [properties](https://github.com/Netflix/Hystrix/wiki/Configuration#Collapser) use `@HystrixCollapser#collapserProperties`\n\nRead more about Hystrix request collapsing [here] (https://github.com/Netflix/Hystrix/wiki/How-it-Works#wiki-RequestCollapsing)\n\n**Collapser error processing**\nBatch command can have a fallback method.\nExample:\n\n```java\n    @HystrixCollapser(batchMethod = \"getUserByIdsWithFallback\")\n    public Future<User> getUserByIdWithFallback(String id) {\n        return null;\n    }\n        \n    @HystrixCommand(fallbackMethod = \"getUserByIdsFallback\")\n    public List<User> getUserByIdsWithFallback(List<String> ids) {\n        throw new RuntimeException(\"not found\");\n    }\n\n\n    @HystrixCommand\n    private List<User> getUserByIdsFallback(List<String> ids) {\n        List<User> users = new ArrayList<User>();\n        for (String id : ids) {\n            users.add(new User(id, \"name: \" + id));\n        }\n        return users;\n    }\n```\n\n\n#Development Status and Future\nPlease create an issue if you need a feature or you detected some bugs. Thanks\n\n**Note**: Javanica 1.4.+ is updated more frequently than 1.3.+ hence 1.4+ is more stable. \n\n**It's recommended to use Javanica 1.4.+** \n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/build.gradle",
    "content": "configurations {\n    ajtools\n    ajcTestImplementation.extendsFrom testCompileClasspath\n    ajcTestRuntimeOnly.extendsFrom testRuntimeClasspath\n    ajc\n}\n\n\nsourceSets {\n    ajcTest {\n        compileClasspath += main.output + test.output\n        runtimeClasspath += main.output + test.output\n    }\n\n    ajc {\n        def main = sourceSets.main\n        java.srcDirs = main.java.srcDirs\n        resources.srcDirs = main.resources.srcDirs\n        compileClasspath = main.compileClasspath\n        runtimeClasspath = main.runtimeClasspath\n    }\n}\n\n\n\ncompileAjcTestJava {\n\n    doLast {\n        ant.taskdef(resource: \"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties\", classpath: configurations.ajtools.asPath)\n        ant.iajc(source: \"1.8\", target: \"1.8\",\n                destDir: \"${sourceSets.ajcTest.output.classesDirs.files.first().absolutePath}\", maxmem: \"512m\", fork: \"true\",\n                classpath: \"${sourceSets.main.output.classesDirs.files.first()absolutePath};${configurations.testCompileClasspath.asPath}\")\n                {\n                    sourceroots {\n                        files(\"src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj\", \"src/test/java/com/netflix/hystrix/contrib/javanica/test/common\", \"src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj\").each {\n                            File file -> pathelement(location: file.absolutePath)\n                        }\n                    }\n                }\n    }\n\n}\n\ncompileAjcJava {\n\n    doLast {\n        ant.taskdef(resource: \"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties\", classpath: configurations.ajtools.asPath)\n        ant.iajc(source: \"${sourceCompatibility}\", target: \"${targetCompatibility}\",\n                destDir: \"${sourceSets.ajc.output.classesDirs.files.first().absolutePath}\", maxmem: \"512m\", fork: \"true\", \"showWeaveInfo\": \"true\",\n                classpath: \"${configurations.compileClasspath.asPath}\")\n\n                {\n                    sourceroots {\n                        sourceSets.ajc.java.srcDirs.each {\n                            pathelement(location: it.absolutePath)\n\n                        }\n                    }\n                }\n    }\n}\n\ntask ajcTest(type: Test) {\n    testClassesDirs = sourceSets.ajcTest.output.classesDirs\n    classpath = sourceSets.ajcTest.runtimeClasspath\n    if (System.getProperty('DEBUG', 'false') == 'true') {\n        jvmArgs '-Xdebug',\n                '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009'\n    }\n}\n\ncheck.dependsOn test, ajcTest\n\n\next {\n    aspectjVersion = '1.8.6'\n    springframeworkVesion = '4.3.2.RELEASE'\n}\n\n\ntask ajcJar(type: Jar) {\n    archiveFileName = \"${project.name}\" + \"-ctw-${version}.jar\"\n    destinationDirectory = file(\"${buildDir}/libs\")\n    from sourceSets.ajc.output\n}\n\nassemble.dependsOn(jar, ajcJar)\n\ndependencies {\n    api project(':hystrix-core')\n    ajtools \"org.aspectj:aspectjtools:$aspectjVersion\"\n    testRuntimeOnly \"org.aspectj:aspectjrt:$aspectjVersion\"\n    api \"org.aspectj:aspectjweaver:$aspectjVersion\"\n    implementation \"org.aspectj:aspectjrt:$aspectjVersion\"\n\n    api 'com.google.guava:guava:15.0'\n    implementation 'org.apache.commons:commons-lang3:3.1'\n    api 'com.google.code.findbugs:jsr305:2.0.0'\n    implementation 'org.ow2.asm:asm:5.0.4'\n    testImplementation group: 'junit', name: 'junit', version: '4.12'\n    testImplementation 'pl.pragmatists:JUnitParams:1.0.5'\n    testImplementation project(':hystrix-junit')\n    testImplementation \"org.springframework:spring-core:$springframeworkVesion\"\n    testImplementation \"org.springframework:spring-context:$springframeworkVesion\"\n    testImplementation \"org.springframework:spring-aop:$springframeworkVesion\"\n    testImplementation \"org.springframework:spring-test:$springframeworkVesion\"\n    testImplementation 'cglib:cglib:3.1'\n    testImplementation 'org.mockito:mockito-all:1.9.5'\n    testImplementation 'log4j:log4j:1.2.17'\n    testImplementation 'org.slf4j:slf4j-log4j12:1.7.7'\n    testImplementation 'com.tngtech.java:junit-dataprovider:1.10.2'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/cache/CacheTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.cache;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.cache.BasicCacheTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class CacheTest extends BasicCacheTest {\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        UserService userService = new UserService();\n        userService.init();\n        return userService;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/collapser/CollapserTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.collapser;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.collapser.BasicCollapserTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class CollapserTest extends BasicCollapserTest {\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/command/CommandTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.command;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.command.BasicCommandTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.BeforeClass;\n\n\npublic class CommandTest extends BasicCommandTest {\n\n    @BeforeClass\n    public static void setUpEnv(){\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n\n    @Override\n    protected AdvancedUserService createAdvancedUserServiceService() {\n        return new AdvancedUserService();\n    }\n\n    @Override\n    protected GenericService<String, Long, User> createGenericUserService() {\n        return new GenericUserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/configuration/collapser/CollapserPropertiesTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.configuration.collapser;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.collapser.BasicCollapserPropertiesTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class CollapserPropertiesTest extends BasicCollapserPropertiesTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/configuration/command/CommandPropertiesTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.configuration.command;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.command.BasicCommandPropertiesTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class CommandPropertiesTest extends BasicCommandPropertiesTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n    \n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/error/ErrorPropagationTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.error;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicErrorPropagationTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class ErrorPropagationTest extends BasicErrorPropagationTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/error/ObservableErrorPropagationTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.error;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicErrorPropagationTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicObservableErrorPropagationTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class ObservableErrorPropagationTest extends BasicObservableErrorPropagationTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/fallback/CommandFallbackTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.fallback.BasicCommandFallbackTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class CommandFallbackTest extends BasicCommandFallbackTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/java/com/netflix/hystrix/contrib/javanica/test/aspectj/observable/ObservableTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.aspectj.observable;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.observable.BasicObservableTest;\nimport org.junit.BeforeClass;\n\n/**\n * Created by dmgcodevil\n */\npublic class ObservableTest extends BasicObservableTest {\n\n    @BeforeClass\n    public static void setUpEnv() {\n        System.setProperty(\"weavingMode\", \"compile\");\n    }\n\n    @Override\n    protected UserService createUserService() {\n        return new UserService();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/resources/dummy.txt",
    "content": "====\n    Copyright 2016 Netflix, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n====\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/ajcTest/resources/log4j.properties",
    "content": "#\n# Copyright 2016 Netflix, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Define the root logger with appender console\nlog4j.rootLogger = ERROR, CONSOLE\n\n# Define the console appender\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.File=${log}/log.out\n\n# Define the layout for console appender\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.conversionPattern=%m%n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/DefaultProperties.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation is used to specify default parameters for\n * hystrix commands (methods annotated with {@code @HystrixCommand} annotation).\n *\n * @author dmgcodevil\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\npublic @interface DefaultProperties {\n\n    /**\n     * Specifies default group key used for each hystrix command by default unless a command specifies group key explicitly.\n     * For additional info about this property see {@link HystrixCommand#groupKey()}.\n     *\n     * @return default group key\n     */\n    String groupKey() default \"\";\n\n    /**\n     * Specifies default thread pool key used for each hystrix command by default unless a command specifies thread pool key explicitly.\n     * For additional info about this property see {@link HystrixCommand#threadPoolKey()}\n     *\n     * @return default thread pool\n     */\n    String threadPoolKey() default \"\";\n\n    /**\n     * Specifies command properties that will be used for\n     * each hystrix command be default unless command properties explicitly specified in @HystrixCommand.\n     *\n     * @return command properties\n     */\n    HystrixProperty[] commandProperties() default {};\n\n    /**\n     * Specifies thread pool properties that will be used for\n     * each hystrix command be default unless thread pool properties explicitly specified in @HystrixCommand.\n     *\n     * @return thread pool properties\n     */\n    HystrixProperty[] threadPoolProperties() default {};\n\n    /**\n     * Defines exceptions which should be ignored.\n     * Optionally these can be wrapped in HystrixRuntimeException if raiseHystrixExceptions contains RUNTIME_EXCEPTION.\n     *\n     * @return exceptions to ignore\n     */\n    Class<? extends Throwable>[] ignoreExceptions() default {};\n\n    /**\n     * When includes RUNTIME_EXCEPTION, any exceptions that are not ignored are wrapped in HystrixRuntimeException.\n     *\n     * @return exceptions to wrap\n     */\n    HystrixException[] raiseHystrixExceptions() default {};\n\n    /**\n     * Specifies default fallback method for each command in the given class. Every command within the class should\n     * have a return type which is compatible with default fallback method return type.\n     * note: default fallback method cannot have parameters.\n     *\n     * @return the name of default fallback method\n     */\n    String defaultFallback() default \"\";\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCollapser.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.annotation;\n\nimport com.netflix.hystrix.HystrixCollapser.Scope;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation is used to collapse some commands into a single backend dependency call.\n * This annotation should be used together with {@link HystrixCommand} annotation.\n * <p/>\n * Example:\n * <pre>\n *     @HystrixCollapser(batchMethod = \"getUserByIds\"){\n *          public Future<User> getUserById(String id) {\n *          return null;\n * }\n *  @HystrixCommand\n *      public List<User> getUserByIds(List<String> ids) {\n *          List<User> users = new ArrayList<User>();\n *          for (String id : ids) {\n *              users.add(new User(id, \"name: \" + id));\n *          }\n *      return users;\n * }\n *   </pre>\n *\n * A method annotated with {@link HystrixCollapser} annotation can return any\n * value with compatible type, it does not affect the result of collapser execution,\n * collapser method can even return {@code null} or another stub.\n * Pay attention that if a collapser method returns parametrized Future then generic type must be equal to generic type of List,\n * for instance:\n * <pre>\n *     Future<User> - return type of collapser method\n *     List<User> - return type of batch command method\n * </pre>\n * <p/>\n * Note: batch command method must be annotated with {@link HystrixCommand} annotation.\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface HystrixCollapser {\n\n    /**\n     * Specifies a collapser key.\n     * <p/>\n     * default => the name of annotated method.\n     *\n     * @return collapser key.\n     */\n    String collapserKey() default \"\";\n\n    /**\n     * Method name of batch command.\n     * <p/>\n     * Method must have the following signature:\n     * <pre>\n     *     java.util.List method(java.util.List)\n     * </pre>\n     * NOTE: batch method can have only one argument.\n     *\n     * @return method name of batch command\n     */\n    String batchMethod();\n\n    /**\n     * Defines what scope the collapsing should occur within.\n     * <p/>\n     * default => the {@link Scope#REQUEST}.\n     *\n     * @return {@link Scope}\n     */\n    Scope scope() default Scope.REQUEST;\n\n    /**\n     * Specifies collapser properties.\n     *\n     * @return collapser properties\n     */\n    HystrixProperty[] collapserProperties() default {};\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n/**\n * This annotation used to specify some methods which should be processes as hystrix commands.\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\npublic @interface HystrixCommand {\n\n    /**\n     * The command group key is used for grouping together commands such as for reporting,\n     * alerting, dashboards or team/library ownership.\n     * <p/>\n     * default => the runtime class name of annotated method\n     *\n     * @return group key\n     */\n    String groupKey() default \"\";\n\n    /**\n     * Hystrix command key.\n     * <p/>\n     * default => the name of annotated method. for example:\n     * <code>\n     *     ...\n     *     @HystrixCommand\n     *     public User getUserById(...)\n     *     ...\n     *     the command name will be: 'getUserById'\n     * </code>\n     *\n     * @return command key\n     */\n    String commandKey() default \"\";\n\n    /**\n     * The thread-pool key is used to represent a\n     * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses.\n     *\n     * @return thread pool key\n     */\n    String threadPoolKey() default \"\";\n\n    /**\n     * Specifies a method to process fallback logic.\n     * A fallback method should be defined in the same class where is HystrixCommand.\n     * Also a fallback method should have same signature to a method which was invoked as hystrix command.\n     * for example:\n     * <code>\n     *      @HystrixCommand(fallbackMethod = \"getByIdFallback\")\n     *      public String getById(String id) {...}\n     *\n     *      private String getByIdFallback(String id) {...}\n     * </code>\n     * Also a fallback method can be annotated with {@link HystrixCommand}\n     * <p/>\n     * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()}\n     *\n     * @return method name\n     */\n    String fallbackMethod() default \"\";\n\n    /**\n     * Specifies command properties.\n     *\n     * @return command properties\n     */\n    HystrixProperty[] commandProperties() default {};\n\n    /**\n     * Specifies thread pool properties.\n     *\n     * @return thread pool properties\n     */\n    HystrixProperty[] threadPoolProperties() default {};\n\n    /**\n     * Defines exceptions which should be ignored.\n     * Optionally these can be wrapped in HystrixRuntimeException if raiseHystrixExceptions contains RUNTIME_EXCEPTION.\n     *\n     * @return exceptions to ignore\n     */\n    Class<? extends Throwable>[] ignoreExceptions() default {};\n\n    /**\n     * Specifies the mode that should be used to execute hystrix observable command.\n     * For more information see {@link ObservableExecutionMode}.\n     *\n     * @return observable execution mode\n     */\n    ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;\n\n    /**\n     * When includes RUNTIME_EXCEPTION, any exceptions that are not ignored are wrapped in HystrixRuntimeException.\n     *\n     * @return exceptions to wrap\n     */\n    HystrixException[] raiseHystrixExceptions() default {};\n\n    /**\n     * Specifies default fallback method for the command. If both {@link #fallbackMethod} and {@link #defaultFallback}\n     * methods are specified then specific one is used.\n     * note: default fallback method cannot have parameters, return type should be compatible with command return type.\n     *\n     * @return the name of default fallback method\n     */\n    String defaultFallback() default \"\";\n}\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixException.java",
    "content": "package com.netflix.hystrix.contrib.javanica.annotation;\n\n/**\n * Created by Mike Cowan\n */\npublic enum HystrixException {\n    RUNTIME_EXCEPTION,\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/HystrixProperty.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation allows specify Hystrix command properties in the following format:\n * property name = property value.\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface HystrixProperty {\n\n    /**\n     * Property name.\n     *\n     * @return name\n     */\n    String name();\n\n    /**\n     * Property value\n     *\n     * @return value\n     */\n    String value();\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/annotation/ObservableExecutionMode.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.annotation;\n\nimport com.netflix.hystrix.HystrixObservable;\nimport rx.Observable;\n\n/**\n * Hystrix observable command can be executed in two different ways:\n * eager - {@link HystrixObservable#observe()},\n * lazy -  {@link HystrixObservable#toObservable()}.\n * <p/>\n * This enum is used to specify desire execution mode.\n * <p/>\n * Created by dmgcodevil.\n */\npublic enum ObservableExecutionMode {\n\n    /**\n     * This mode lazily starts execution of the command only once the {@link Observable} is subscribed to.\n     */\n    LAZY,\n\n    /**\n     * This mode eagerly starts execution of the command the same as {@link com.netflix.hystrix.HystrixCommand#queue()}\n     * and {@link com.netflix.hystrix.HystrixCommand#execute()}.\n     */\n    EAGER\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCacheAspect.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.aop.aspectj;\n\n\nimport com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContext;\nimport com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContextFactory;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixRequestCacheManager;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.command.ExecutionType;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport org.apache.commons.lang3.Validate;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\n\nimport java.lang.reflect.Method;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodFromTarget;\nimport static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;\nimport static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.getAjcMethodAroundAdvice;\n\n/**\n * AspectJ aspect to process methods which annotated with annotations from\n * <code>com.netflix.hystrix.contrib.javanica.cache.annotation</code> package.\n *\n * @author dmgcodevil\n */\n@Aspect\npublic class HystrixCacheAspect {\n\n    @Pointcut(\"@annotation(com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove) && !@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)\")\n    public void cacheRemoveAnnotationPointcut() {\n    }\n\n    @Around(\"cacheRemoveAnnotationPointcut()\")\n    public Object methodsAnnotatedWithCacheRemove(final ProceedingJoinPoint joinPoint) throws Throwable {\n        Method method = getMethodFromTarget(joinPoint);\n        Object obj = joinPoint.getTarget();\n        Object[] args = joinPoint.getArgs();\n        Validate.notNull(method, \"failed to get method from joinPoint: %s\", joinPoint);\n        MetaHolder metaHolder = MetaHolder.builder()\n                .args(args).method(method).obj(obj)\n                .executionType(ExecutionType.SYNCHRONOUS)\n                .ajcMethod(isCompileWeaving() ? getAjcMethodAroundAdvice(obj.getClass(), method) : null)\n                .build();\n        CacheInvocationContext<CacheRemove> context = CacheInvocationContextFactory\n                .createCacheRemoveInvocationContext(metaHolder);\n        HystrixRequestCacheManager.getInstance().clearCache(context);\n        return joinPoint.proceed();\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.aop.aspectj;\n\nimport com.google.common.base.Optional;\nimport com.google.common.collect.ImmutableMap;\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixException;\nimport com.netflix.hystrix.contrib.javanica.command.CommandExecutor;\nimport com.netflix.hystrix.contrib.javanica.command.ExecutionType;\nimport com.netflix.hystrix.contrib.javanica.command.HystrixCommandFactory;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackInvocationException;\nimport com.netflix.hystrix.contrib.javanica.utils.AopUtils;\nimport com.netflix.hystrix.contrib.javanica.utils.FallbackMethod;\nimport com.netflix.hystrix.contrib.javanica.utils.MethodProvider;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.Validate;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport rx.Completable;\nimport rx.Observable;\nimport rx.Single;\nimport rx.functions.Func1;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Future;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getDeclaredMethod;\nimport static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodFromTarget;\nimport static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodInfo;\nimport static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;\nimport static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.getAjcMethodAroundAdvice;\n\n/**\n * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation.\n */\n@Aspect\npublic class HystrixCommandAspect {\n\n    private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;\n\n    static {\n        META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()\n                .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())\n                .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())\n                .build();\n    }\n\n    @Pointcut(\"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)\")\n\n    public void hystrixCommandAnnotationPointcut() {\n    }\n\n    @Pointcut(\"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)\")\n    public void hystrixCollapserAnnotationPointcut() {\n    }\n\n    @Around(\"hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()\")\n    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {\n        Method method = getMethodFromTarget(joinPoint);\n        Validate.notNull(method, \"failed to get method from joinPoint: %s\", joinPoint);\n        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {\n            throw new IllegalStateException(\"method cannot be annotated with HystrixCommand and HystrixCollapser \" +\n                    \"annotations at the same time\");\n        }\n        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));\n        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);\n        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);\n        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?\n                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();\n\n        Object result;\n        try {\n            if (!metaHolder.isObservable()) {\n                result = CommandExecutor.execute(invokable, executionType, metaHolder);\n            } else {\n                result = executeObservable(invokable, executionType, metaHolder);\n            }\n        } catch (HystrixBadRequestException e) {\n            throw e.getCause() != null ? e.getCause() : e;\n        } catch (HystrixRuntimeException e) {\n            throw hystrixRuntimeExceptionToThrowable(metaHolder, e);\n        }\n        return result;\n    }\n\n    private Object executeObservable(HystrixInvokable invokable, ExecutionType executionType, final MetaHolder metaHolder) {\n        return mapObservable(((Observable) CommandExecutor.execute(invokable, executionType, metaHolder))\n                .onErrorResumeNext(new Func1<Throwable, Observable>() {\n                    @Override\n                    public Observable call(Throwable throwable) {\n                        if (throwable instanceof HystrixBadRequestException) {\n                            return Observable.error(throwable.getCause());\n                        } else if (throwable instanceof HystrixRuntimeException) {\n                            HystrixRuntimeException hystrixRuntimeException = (HystrixRuntimeException) throwable;\n                            return Observable.error(hystrixRuntimeExceptionToThrowable(metaHolder, hystrixRuntimeException));\n                        }\n                        return Observable.error(throwable);\n                    }\n                }), metaHolder);\n    }\n\n    private Object mapObservable(Observable observable, final MetaHolder metaHolder) {\n        if (Completable.class.isAssignableFrom(metaHolder.getMethod().getReturnType())) {\n            return observable.toCompletable();\n        } else if (Single.class.isAssignableFrom(metaHolder.getMethod().getReturnType())) {\n            return observable.toSingle();\n        }\n        return observable;\n    }\n\n    private Throwable hystrixRuntimeExceptionToThrowable(MetaHolder metaHolder, HystrixRuntimeException e) {\n        if (metaHolder.raiseHystrixExceptionsContains(HystrixException.RUNTIME_EXCEPTION)) {\n            return e;\n        }\n        return getCause(e);\n    }\n\n    private Throwable getCause(HystrixRuntimeException e) {\n        if (e.getFailureType() != HystrixRuntimeException.FailureType.COMMAND_EXCEPTION) {\n            return e;\n        }\n\n        Throwable cause = e.getCause();\n\n        // latest exception in flow should be propagated to end user\n        if (e.getFallbackException() instanceof FallbackInvocationException) {\n            cause = e.getFallbackException().getCause();\n            if (cause instanceof HystrixRuntimeException) {\n                cause = getCause((HystrixRuntimeException) cause);\n            }\n        } else if (cause instanceof CommandActionExecutionException) { // this situation is possible only if a callee throws an exception which type extends Throwable directly\n            CommandActionExecutionException commandActionExecutionException = (CommandActionExecutionException) cause;\n            cause = commandActionExecutionException.getCause();\n        }\n\n        return Optional.fromNullable(cause).or(e);\n    }\n\n    /**\n     * A factory to create MetaHolder depending on {@link HystrixPointcutType}.\n     */\n    private static abstract class MetaHolderFactory {\n        public MetaHolder create(final ProceedingJoinPoint joinPoint) {\n            Method method = getMethodFromTarget(joinPoint);\n            Object obj = joinPoint.getTarget();\n            Object[] args = joinPoint.getArgs();\n            Object proxy = joinPoint.getThis();\n            return create(proxy, method, obj, args, joinPoint);\n        }\n\n        public abstract MetaHolder create(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint);\n\n        MetaHolder.Builder metaHolderBuilder(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {\n            MetaHolder.Builder builder = MetaHolder.builder()\n                    .args(args).method(method).obj(obj).proxyObj(proxy)\n                    .joinPoint(joinPoint);\n\n            setFallbackMethod(builder, obj.getClass(), method);\n            builder = setDefaultProperties(builder, obj.getClass(), joinPoint);\n            return builder;\n        }\n    }\n\n    private static class CollapserMetaHolderFactory extends MetaHolderFactory {\n\n        @Override\n        public MetaHolder create(Object proxy, Method collapserMethod, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {\n            HystrixCollapser hystrixCollapser = collapserMethod.getAnnotation(HystrixCollapser.class);\n            if (collapserMethod.getParameterTypes().length > 1 || collapserMethod.getParameterTypes().length == 0) {\n                throw new IllegalStateException(\"Collapser method must have one argument: \" + collapserMethod);\n            }\n\n            Method batchCommandMethod = getDeclaredMethod(obj.getClass(), hystrixCollapser.batchMethod(), List.class);\n\n            if (batchCommandMethod == null)\n                throw new IllegalStateException(\"batch method is absent: \" + hystrixCollapser.batchMethod());\n\n            Class<?> batchReturnType = batchCommandMethod.getReturnType();\n            Class<?> collapserReturnType = collapserMethod.getReturnType();\n            boolean observable = collapserReturnType.equals(Observable.class);\n\n            if (!collapserMethod.getParameterTypes()[0]\n                    .equals(getFirstGenericParameter(batchCommandMethod.getGenericParameterTypes()[0]))) {\n                throw new IllegalStateException(\"required batch method for collapser is absent, wrong generic type: expected \"\n                        + obj.getClass().getCanonicalName() + \".\" +\n                        hystrixCollapser.batchMethod() + \"(java.util.List<\" + collapserMethod.getParameterTypes()[0] + \">), but it's \" +\n                        getFirstGenericParameter(batchCommandMethod.getGenericParameterTypes()[0]));\n            }\n\n            final Class<?> collapserMethodReturnType = getFirstGenericParameter(\n                    collapserMethod.getGenericReturnType(),\n                    Future.class.isAssignableFrom(collapserReturnType) || Observable.class.isAssignableFrom(collapserReturnType) ? 1 : 0);\n\n            Class<?> batchCommandActualReturnType = getFirstGenericParameter(batchCommandMethod.getGenericReturnType());\n            if (!collapserMethodReturnType\n                    .equals(batchCommandActualReturnType)) {\n                throw new IllegalStateException(\"Return type of batch method must be java.util.List parametrized with corresponding type: expected \" +\n                        \"(java.util.List<\" + collapserMethodReturnType + \">)\" + obj.getClass().getCanonicalName() + \".\" +\n                        hystrixCollapser.batchMethod() + \"(java.util.List<\" + collapserMethod.getParameterTypes()[0] + \">), but it's \" +\n                        batchCommandActualReturnType);\n            }\n\n            HystrixCommand hystrixCommand = batchCommandMethod.getAnnotation(HystrixCommand.class);\n            if (hystrixCommand == null) {\n                throw new IllegalStateException(\"batch method must be annotated with HystrixCommand annotation\");\n            }\n            // method of batch hystrix command must be passed to metaholder because basically collapser doesn't have any actions\n            // that should be invoked upon intercepted method, it's required only for underlying batch command\n\n            MetaHolder.Builder builder = metaHolderBuilder(proxy, batchCommandMethod, obj, args, joinPoint);\n\n            if (isCompileWeaving()) {\n                builder.ajcMethod(getAjcMethodAroundAdvice(obj.getClass(), batchCommandMethod.getName(), List.class));\n            }\n\n            builder.hystrixCollapser(hystrixCollapser);\n            builder.defaultCollapserKey(collapserMethod.getName());\n            builder.collapserExecutionType(ExecutionType.getExecutionType(collapserReturnType));\n\n            builder.defaultCommandKey(batchCommandMethod.getName());\n            builder.hystrixCommand(hystrixCommand);\n            builder.executionType(ExecutionType.getExecutionType(batchReturnType));\n            builder.observable(observable);\n            FallbackMethod fallbackMethod = MethodProvider.getInstance().getFallbackMethod(obj.getClass(), batchCommandMethod);\n            if (fallbackMethod.isPresent()) {\n                fallbackMethod.validateReturnType(batchCommandMethod);\n                builder\n                        .fallbackMethod(fallbackMethod.getMethod())\n                        .fallbackExecutionType(ExecutionType.getExecutionType(fallbackMethod.getMethod().getReturnType()));\n            }\n            return builder.build();\n        }\n    }\n\n    private static class CommandMetaHolderFactory extends MetaHolderFactory {\n        @Override\n        public MetaHolder create(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {\n            HystrixCommand hystrixCommand = method.getAnnotation(HystrixCommand.class);\n            ExecutionType executionType = ExecutionType.getExecutionType(method.getReturnType());\n            MetaHolder.Builder builder = metaHolderBuilder(proxy, method, obj, args, joinPoint);\n            if (isCompileWeaving()) {\n                builder.ajcMethod(getAjcMethodFromTarget(joinPoint));\n            }\n            return builder.defaultCommandKey(method.getName())\n                            .hystrixCommand(hystrixCommand)\n                            .observableExecutionMode(hystrixCommand.observableExecutionMode())\n                            .executionType(executionType)\n                            .observable(ExecutionType.OBSERVABLE == executionType)\n                            .build();\n        }\n    }\n\n    private enum HystrixPointcutType {\n        COMMAND,\n        COLLAPSER;\n\n        static HystrixPointcutType of(Method method) {\n            if (method.isAnnotationPresent(HystrixCommand.class)) {\n                return COMMAND;\n            } else if (method.isAnnotationPresent(HystrixCollapser.class)) {\n                return COLLAPSER;\n            } else {\n                String methodInfo = getMethodInfo(method);\n                throw new IllegalStateException(\"'https://github.com/Netflix/Hystrix/issues/1458' - no valid annotation found for: \\n\" + methodInfo);\n            }\n        }\n    }\n\n    private static Method getAjcMethodFromTarget(JoinPoint joinPoint) {\n        return getAjcMethodAroundAdvice(joinPoint.getTarget().getClass(), (MethodSignature) joinPoint.getSignature());\n    }\n\n\n    private static Class<?> getFirstGenericParameter(Type type) {\n        return getFirstGenericParameter(type, 1);\n    }\n\n    private static Class<?> getFirstGenericParameter(final Type type, final int nestedDepth) {\n        int cDepth = 0;\n        Type tType = type;\n\n        for (int cDept = 0; cDept < nestedDepth; cDept++) {\n            if (!(tType instanceof ParameterizedType))\n                throw new IllegalStateException(String.format(\"Sub type at nesting level %d of %s is expected to be generic\", cDepth, type));\n            tType = ((ParameterizedType) tType).getActualTypeArguments()[cDept];\n        }\n\n        if (tType instanceof ParameterizedType)\n            return (Class<?>) ((ParameterizedType) tType).getRawType();\n        else if (tType instanceof Class)\n            return (Class<?>) tType;\n\n        throw new UnsupportedOperationException(\"Unsupported type \" + tType);\n    }\n\n    private static MetaHolder.Builder setDefaultProperties(MetaHolder.Builder builder, Class<?> declaringClass, final ProceedingJoinPoint joinPoint) {\n        Optional<DefaultProperties> defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);\n        builder.defaultGroupKey(declaringClass.getSimpleName());\n        if (defaultPropertiesOpt.isPresent()) {\n            DefaultProperties defaultProperties = defaultPropertiesOpt.get();\n            builder.defaultProperties(defaultProperties);\n            if (StringUtils.isNotBlank(defaultProperties.groupKey())) {\n                builder.defaultGroupKey(defaultProperties.groupKey());\n            }\n            if (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {\n                builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());\n            }\n        }\n        return builder;\n    }\n\n    private static MetaHolder.Builder setFallbackMethod(MetaHolder.Builder builder, Class<?> declaringClass, Method commandMethod) {\n        FallbackMethod fallbackMethod = MethodProvider.getInstance().getFallbackMethod(declaringClass, commandMethod);\n        if (fallbackMethod.isPresent()) {\n            fallbackMethod.validateReturnType(commandMethod);\n            builder\n                    .fallbackMethod(fallbackMethod.getMethod())\n                    .fallbackExecutionType(ExecutionType.getExecutionType(fallbackMethod.getMethod().getReturnType()));\n        }\n        return builder;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/WeavingMode.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.aop.aspectj;\n\n/**\n * Created by dmgcodevil\n */\npublic enum WeavingMode {\n\n    COMPILE, RUNTIME\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationContext.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.google.common.base.Predicate;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.collect.Iterables;\nimport com.netflix.hystrix.contrib.javanica.command.ExecutionType;\nimport com.netflix.hystrix.contrib.javanica.command.MethodExecutionAction;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Runtime information about an intercepted method invocation for a method\n * annotated with {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult},\n * {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove} annotations.\n *\n * @author dmgcodevil\n */\npublic class CacheInvocationContext<A extends Annotation> {\n\n    private final Method method;\n    private final Object target;\n    private final MethodExecutionAction cacheKeyMethod;\n    private final ExecutionType executionType = ExecutionType.SYNCHRONOUS;\n    private final A cacheAnnotation;\n\n    private List<CacheInvocationParameter> parameters = Collections.emptyList();\n    private List<CacheInvocationParameter> keyParameters = Collections.emptyList();\n\n    /**\n     * Constructor to create CacheInvocationContext based on passed parameters.\n     *\n     * @param cacheAnnotation the caching annotation, like {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult}\n     * @param cacheKeyMethod  the method to generate cache key\n     * @param target          the current instance of intercepted method\n     * @param method          the method annotated with on of caching annotations\n     * @param args            the method arguments\n     */\n    public CacheInvocationContext(A cacheAnnotation, MethodExecutionAction cacheKeyMethod, Object target, Method method, Object... args) {\n        this.method = method;\n        this.target = target;\n        this.cacheKeyMethod = cacheKeyMethod;\n        this.cacheAnnotation = cacheAnnotation;\n        Class<?>[] parametersTypes = method.getParameterTypes();\n        int parameterCount = parametersTypes.length;\n        if (parameterCount > 0) {\n            Annotation[][] parametersAnnotations = method.getParameterAnnotations();\n            ImmutableList.Builder<CacheInvocationParameter> parametersBuilder = ImmutableList.builder();\n            for (int pos = 0; pos < parameterCount; pos++) {\n                Class<?> paramType = parametersTypes[pos];\n                Object val = args[pos];\n                parametersBuilder.add(new CacheInvocationParameter(paramType, val, parametersAnnotations[pos], pos));\n            }\n            parameters = parametersBuilder.build();\n            // get key parameters\n            Iterable<CacheInvocationParameter> filtered = Iterables.filter(parameters, new Predicate<CacheInvocationParameter>() {\n                @Override\n                public boolean apply(CacheInvocationParameter input) {\n                    return input.hasCacheKeyAnnotation();\n                }\n            });\n            if (filtered.iterator().hasNext()) {\n                keyParameters = ImmutableList.<CacheInvocationParameter>builder().addAll(filtered).build();\n            } else {\n                keyParameters = parameters;\n            }\n        }\n    }\n\n    /**\n     * Gets intercepted method that annotated with caching annotation.\n     *\n     * @return method\n     */\n    public Method getMethod() {\n        return method;\n    }\n\n    /**\n     * Gets current instance that can be used to invoke {@link #cacheKeyMethod} or for another needs.\n     *\n     * @return current instance\n     */\n    public Object getTarget() {\n        return target;\n    }\n\n    public A getCacheAnnotation() {\n        return cacheAnnotation;\n    }\n\n    /**\n     * Gets all method parameters.\n     *\n     * @return immutable list of {@link CacheInvocationParameter} objects\n     */\n    public List<CacheInvocationParameter> getAllParameters() {\n        return parameters;\n    }\n\n    /**\n     * Returns a clone of the array of all method parameters annotated with\n     * {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey} annotation to be used by the\n     * {@link HystrixCacheKeyGenerator} in creating a {@link HystrixGeneratedCacheKey}. The returned array\n     * may be the same as or a subset of the array returned by {@link #getAllParameters()}.\n     * <p/>\n     * Parameters in this array are selected by the following rules:\n     * <ul>\n     * <li>If no parameters are annotated with {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey}\n     * then all parameters are included</li>\n     * <li>If one or more {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey} annotations exist only those parameters\n     * with the {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey} annotation are included</li>\n     * </ul>\n     *\n     * @return immutable list of {@link CacheInvocationParameter} objects\n     */\n    public List<CacheInvocationParameter> getKeyParameters() {\n        return keyParameters;\n    }\n\n    /**\n     * Checks whether any method argument annotated with {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey} annotation.\n     *\n     * @return true if at least one method argument with {@link com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey} annotation\n     */\n    public boolean hasKeyParameters() {\n        return !keyParameters.isEmpty();\n    }\n\n    /**\n     * Gets method name to be used to get a key for request caching.\n     *\n     * @return method name\n     */\n    public String getCacheKeyMethodName() {\n        return cacheKeyMethod != null ? cacheKeyMethod.getMethod().getName() : null;\n    }\n\n    /**\n     * Gets action that invokes cache key method, the result of execution is used as cache key.\n     *\n     * @return cache key method execution action, see {@link MethodExecutionAction}.\n     */\n    public MethodExecutionAction getCacheKeyMethod() {\n        return cacheKeyMethod;\n    }\n\n    /**\n     * Gets execution type of cache key action.\n     *\n     * @return execution type\n     */\n    public ExecutionType getExecutionType() {\n        return executionType;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationContextFactory.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport com.netflix.hystrix.contrib.javanica.command.MethodExecutionAction;\nimport com.netflix.hystrix.contrib.javanica.exception.HystrixCachingException;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.lang.reflect.Method;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getDeclaredMethod;\n\n/**\n * Factory to create certain {@link CacheInvocationContext}.\n *\n * @author dmgcodevil\n */\npublic class CacheInvocationContextFactory {\n\n    /**\n     * Create {@link CacheInvocationContext} parametrized with {@link CacheResult} annotation.\n     *\n     * @param metaHolder the meta holder, see {@link com.netflix.hystrix.contrib.javanica.command.MetaHolder}\n     * @return initialized and configured {@link CacheInvocationContext}\n     */\n    public static CacheInvocationContext<CacheResult> createCacheResultInvocationContext(MetaHolder metaHolder) {\n        Method method = metaHolder.getMethod();\n        if (method.isAnnotationPresent(CacheResult.class)) {\n            CacheResult cacheResult = method.getAnnotation(CacheResult.class);\n            MethodExecutionAction cacheKeyMethod = createCacheKeyAction(cacheResult.cacheKeyMethod(), metaHolder);\n            return new CacheInvocationContext<CacheResult>(cacheResult, cacheKeyMethod, metaHolder.getObj(), method, metaHolder.getArgs());\n        }\n        return null;\n    }\n\n    /**\n     * Create {@link CacheInvocationContext} parametrized with {@link CacheRemove} annotation.\n     *\n     * @param metaHolder the meta holder, see {@link com.netflix.hystrix.contrib.javanica.command.MetaHolder}\n     * @return initialized and configured {@link CacheInvocationContext}\n     */\n    public static CacheInvocationContext<CacheRemove> createCacheRemoveInvocationContext(MetaHolder metaHolder) {\n        Method method = metaHolder.getMethod();\n        if (method.isAnnotationPresent(CacheRemove.class)) {\n            CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);\n            MethodExecutionAction cacheKeyMethod = createCacheKeyAction(cacheRemove.cacheKeyMethod(), metaHolder);\n            return new CacheInvocationContext<CacheRemove>(cacheRemove, cacheKeyMethod, metaHolder.getObj(), method, metaHolder.getArgs());\n        }\n        return null;\n    }\n\n    private static MethodExecutionAction createCacheKeyAction(String method, MetaHolder metaHolder) {\n        MethodExecutionAction cacheKeyAction = null;\n        if (StringUtils.isNotBlank(method)) {\n            Method cacheKeyMethod = getDeclaredMethod(metaHolder.getObj().getClass(), method,\n                    metaHolder.getMethod().getParameterTypes());\n            if (cacheKeyMethod == null) {\n                throw new HystrixCachingException(\"method with name '\" + method + \"' doesn't exist in class '\"\n                        + metaHolder.getObj().getClass() + \"'\");\n            }\n            if (!cacheKeyMethod.getReturnType().equals(String.class)) {\n                throw new HystrixCachingException(\"return type of cacheKey method must be String. Method: '\" + method + \"', Class: '\"\n                        + metaHolder.getObj().getClass() + \"'\");\n            }\n\n            MetaHolder cMetaHolder = MetaHolder.builder().obj(metaHolder.getObj()).method(cacheKeyMethod).args(metaHolder.getArgs()).build();\n            cacheKeyAction = new MethodExecutionAction(cMetaHolder.getObj(), cacheKeyMethod, cMetaHolder.getArgs(), cMetaHolder);\n        }\n        return cacheKeyAction;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationParameter.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.google.common.base.Predicate;\nimport com.google.common.collect.ImmutableSet;\nimport com.google.common.collect.Iterables;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Arrays;\nimport java.util.Set;\n\n/**\n * A parameter to an intercepted method invocation. Contains the parameter value\n * as well static type and annotation information about the parameter.\n *\n * @author dmgcodevil\n */\npublic class CacheInvocationParameter {\n\n    private final Class<?> rawType;\n    private final Object value;\n    private final CacheKey cacheKeyAnnotation;\n    private final Set<Annotation> annotations;\n    private final int position;\n\n    public CacheInvocationParameter(Class<?> rawType, Object value, Annotation[] annotations, int position) {\n        this.rawType = rawType;\n        this.value = value;\n        this.annotations = ImmutableSet.<Annotation>builder().addAll(Arrays.asList(annotations)).build();\n        this.position = position;\n        this.cacheKeyAnnotation = (CacheKey) cacheKeyAnnotation();\n    }\n\n    /**\n     * Returns an immutable Set of all Annotations on this method parameter, never null.\n     *\n     * @return set of {@link Annotation}\n     */\n    public Set<Annotation> getAnnotations() {\n        return annotations;\n    }\n\n    /**\n     * Gets {@link CacheKey} for the parameter.\n     *\n     * @return {@link CacheKey} annotation or null if the parameter isn't annotated with {@link CacheKey}.\n     */\n    public CacheKey getCacheKeyAnnotation() {\n        return cacheKeyAnnotation;\n    }\n\n    /**\n     * Checks whether the parameter annotated with {@link CacheKey} or not.\n     *\n     * @return true if parameter annotated with {@link CacheKey}  otherwise - false\n     */\n    public boolean hasCacheKeyAnnotation() {\n        return cacheKeyAnnotation != null;\n    }\n\n    /**\n     * Gets the parameter type as declared on the method.\n     *\n     * @return parameter type\n     */\n    public Class<?> getRawType() {\n        return rawType;\n    }\n\n    /**\n     * Gets the parameter value\n     *\n     * @return parameter value\n     */\n    public Object getValue() {\n        return value;\n    }\n\n    /**\n     * Gets index of the parameter in the original parameter array.\n     *\n     * @return index of the parameter\n     */\n    public int getPosition() {\n        return position;\n    }\n\n    private Annotation cacheKeyAnnotation() {\n        return Iterables.tryFind(annotations, new Predicate<Annotation>() {\n            @Override\n            public boolean apply(Annotation input) {\n                return input.annotationType().equals(CacheKey.class);\n            }\n        }).orNull();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/DefaultHystrixGeneratedCacheKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.google.common.base.Objects;\n\n/**\n * Default implementation of {@link HystrixGeneratedCacheKey}.\n *\n * @author dmgcodevil\n */\npublic class DefaultHystrixGeneratedCacheKey implements HystrixGeneratedCacheKey {\n\n    /**\n     * Means \"do not cache\".\n     */\n    public static final DefaultHystrixGeneratedCacheKey EMPTY = new DefaultHystrixGeneratedCacheKey(null);\n\n    private String cacheKey;\n\n    public DefaultHystrixGeneratedCacheKey(String cacheKey) {\n        this.cacheKey = cacheKey;\n    }\n\n    @Override\n    public String getCacheKey() {\n        return cacheKey;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(cacheKey);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        DefaultHystrixGeneratedCacheKey that = (DefaultHystrixGeneratedCacheKey) o;\n\n        return Objects.equal(this.cacheKey, that.cacheKey);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/HystrixCacheKeyGenerator.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\n\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\nimport com.netflix.hystrix.contrib.javanica.command.MethodExecutionAction;\nimport com.netflix.hystrix.contrib.javanica.exception.HystrixCacheKeyGenerationException;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.beans.IntrospectionException;\nimport java.beans.PropertyDescriptor;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Generates a {@link HystrixGeneratedCacheKey} based on\n * a {@link CacheInvocationContext}.\n * <p/>\n * Implementation is thread-safe.\n *\n * @author dmgcodevil\n */\npublic class HystrixCacheKeyGenerator {\n\n    private static final HystrixCacheKeyGenerator INSTANCE = new HystrixCacheKeyGenerator();\n\n    public static HystrixCacheKeyGenerator getInstance() {\n        return INSTANCE;\n    }\n\n    public HystrixGeneratedCacheKey generateCacheKey(CacheInvocationContext<? extends Annotation> cacheInvocationContext) throws HystrixCacheKeyGenerationException {\n        MethodExecutionAction cacheKeyMethod = cacheInvocationContext.getCacheKeyMethod();\n        if (cacheKeyMethod != null) {\n            try {\n                return new DefaultHystrixGeneratedCacheKey((String) cacheKeyMethod.execute(cacheInvocationContext.getExecutionType()));\n            } catch (Throwable throwable) {\n                throw new HystrixCacheKeyGenerationException(throwable);\n            }\n        } else {\n            if (cacheInvocationContext.hasKeyParameters()) {\n                StringBuilder cacheKeyBuilder = new StringBuilder();\n                for (CacheInvocationParameter parameter : cacheInvocationContext.getKeyParameters()) {\n                    CacheKey cacheKey = parameter.getCacheKeyAnnotation();\n                    if (cacheKey != null && StringUtils.isNotBlank(cacheKey.value())) {\n                        appendPropertyValue(cacheKeyBuilder, Arrays.asList(StringUtils.split(cacheKey.value(), \".\")), parameter.getValue());\n                    } else {\n                        cacheKeyBuilder.append(parameter.getValue());\n                    }\n                }\n                return new DefaultHystrixGeneratedCacheKey(cacheKeyBuilder.toString());\n            } else {\n                return DefaultHystrixGeneratedCacheKey.EMPTY;\n            }\n        }\n    }\n\n    private Object appendPropertyValue(StringBuilder cacheKeyBuilder, List<String> names, Object obj) throws HystrixCacheKeyGenerationException {\n        for (String name : names) {\n            if (obj != null) {\n                obj = getPropertyValue(name, obj);\n            }\n        }\n        if (obj != null) {\n            cacheKeyBuilder.append(obj);\n        }\n        return obj;\n    }\n\n    private Object getPropertyValue(String name, Object obj) throws HystrixCacheKeyGenerationException {\n        try {\n            return new PropertyDescriptor(name, obj.getClass())\n                    .getReadMethod().invoke(obj);\n        } catch (IllegalAccessException e) {\n            throw new HystrixCacheKeyGenerationException(e);\n        } catch (IntrospectionException e) {\n            throw new HystrixCacheKeyGenerationException(e);\n        } catch (InvocationTargetException e) {\n            throw new HystrixCacheKeyGenerationException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/HystrixGeneratedCacheKey.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\n/**\n * Specific interface to adopt {@link HystrixGeneratedCacheKey} for Hystrix environment.\n *\n * @author dmgcodevil\n */\npublic interface HystrixGeneratedCacheKey  {\n\n    /**\n     * Key to be used for request caching.\n     * <p/>\n     * By default this returns null which means \"do not cache\".\n     * <p/>\n     * To enable caching override this method and return a string key uniquely representing the state of a command instance.\n     * <p/>\n     * If multiple command instances in the same request scope match keys then only the first will be executed and all others returned from cache.\n     *\n     * @return cacheKey\n     */\n    String getCacheKey();\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/HystrixRequestCacheManager.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixRequestCache;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;\n\n\n/**\n * Cache manager to work with {@link HystrixRequestCache}.\n *\n * @author dmgcodevil\n */\npublic final class HystrixRequestCacheManager {\n\n    private static final HystrixRequestCacheManager INSTANCE = new HystrixRequestCacheManager();\n\n    private HystrixRequestCacheManager() {\n    }\n\n    public static HystrixRequestCacheManager getInstance() {\n        return INSTANCE;\n    }\n\n    /**\n     * Clears the cache for a given cacheKey context.\n     *\n     * @param context the runtime information about an intercepted method invocation for a method\n     *                annotated with {@link CacheRemove} annotation\n     */\n    public void clearCache(CacheInvocationContext<CacheRemove> context) {\n        HystrixCacheKeyGenerator defaultCacheKeyGenerator = HystrixCacheKeyGenerator.getInstance();\n        String cacheName = context.getCacheAnnotation().commandKey();\n        HystrixGeneratedCacheKey hystrixGeneratedCacheKey =\n                defaultCacheKeyGenerator.generateCacheKey(context);\n        String key = hystrixGeneratedCacheKey.getCacheKey();\n        HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(cacheName),\n                HystrixConcurrencyStrategyDefault.getInstance()).clear(key);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/annotation/CacheKey.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks a method argument as part of the cache key.\n * If no arguments are marked all arguments are used.\n * If {@link CacheResult} or {@link CacheRemove} annotation has specified <code>cacheKeyMethod</code> then\n * a method arguments will not be used to build cache key even if they annotated with {@link CacheKey}.\n *\n * @author dmgcodevil\n */\n@Target({ElementType.PARAMETER})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface CacheKey {\n\n    /**\n     * Allows specify name of a certain argument property.\n     * for example: <code>@CacheKey(\"id\") User user</code>,\n     * or in case composite property: <code>@CacheKey(\"profile.name\") User user</code>.\n     * <code>null</code> properties are ignored, i.e. if <code>profile</code> is <code>null</code>\n     * then result of <code>@CacheKey(\"profile.name\") User user</code> will be empty string.\n     *\n     * @return name of an argument property\n     */\n    String value() default \"\";\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/annotation/CacheRemove.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks methods used to invalidate cache of a command.\n * Generated cache key must be same as key generated within {@link CacheResult} context.\n *\n * @author dmgcodevil\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.METHOD})\n@Documented\npublic @interface CacheRemove {\n\n    /**\n     * Command name is used to find appropriate Hystrix command that cache should be cleared.\n     *\n     * @return command name\n     */\n    String commandKey();\n\n    /**\n     * Method name to be used to get a key for request caching.\n     * The command and cache key method should be placed in the same class and have same method signature except\n     * cache key method return type, that should be <code>String</code>.\n     * <p/>\n     * cacheKeyMethod has higher priority than an arguments of a method, that means what actual arguments\n     * of a method that annotated with {@link CacheResult} will not be used to generate cache key, instead specified\n     * cacheKeyMethod fully assigns to itself responsibility for cache key generation.\n     * By default this returns empty string which means \"do not use cache method\".\n     *\n     * @return method name or empty string\n     */\n    String cacheKeyMethod() default \"\";\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/annotation/CacheResult.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks a methods that results should be cached for a Hystrix command.\n * This annotation must be used in conjunction with {@link com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand} annotation.\n *\n * @author dmgcodevil\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface CacheResult {\n\n    /**\n     * Method name to be used to get a key for request caching.\n     * The command and cache key method should be placed in the same class and have same method signature except\n     * cache key method return type, that should be <code>String</code>.\n     * <p/>\n     * cacheKeyMethod has higher priority than an arguments of a method, that means what actual arguments\n     * of a method that annotated with {@link CacheResult} will not be used to generate cache key, instead specified\n     * cacheKeyMethod fully assigns to itself responsibility for cache key generation.\n     * By default this returns empty string which means \"do not use cache method\".\n     *\n     * @return method name or empty string\n     */\n    String cacheKeyMethod() default \"\";\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/collapser/CommandCollapser.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.collapser;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.command.BatchHystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.command.HystrixCommandBuilderFactory;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport static org.slf4j.helpers.MessageFormatter.arrayFormat;\n\n/**\n * Collapses multiple requests into a single {@link HystrixCommand} execution based\n * on a time window and optionally a max batch size.\n */\npublic class CommandCollapser extends HystrixCollapser<List<Object>, Object, Object> {\n\n    private MetaHolder metaHolder;\n\n    private static final String ERROR_MSG = \"Failed to map all collapsed requests to response. \" +\n            \"The expected contract has not been respected. \";\n\n    private static final String ERROR_MSF_TEMPLATE = \"Collapser key: '{}', requests size: '{}', response size: '{}'\";\n\n    /**\n     * Constructor with parameters.\n     *\n     * @param metaHolder the {@link MetaHolder}\n     */\n    public CommandCollapser(MetaHolder metaHolder) {\n        super(HystrixCommandBuilderFactory.getInstance().create(metaHolder).getSetterBuilder().buildCollapserCommandSetter());\n        this.metaHolder = metaHolder;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Object getRequestArgument() {\n        return metaHolder.getArgs();\n    }\n\n    /**\n     * Creates batch command.\n     */\n    @Override\n    protected HystrixCommand<List<Object>> createCommand(\n            Collection<CollapsedRequest<Object, Object>> collapsedRequests) {\n       return new BatchHystrixCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder, collapsedRequests));\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected void mapResponseToRequests(List<Object> batchResponse,\n                                         Collection<CollapsedRequest<Object, Object>> collapsedRequests) {\n        if (batchResponse.size() < collapsedRequests.size()) {\n            throw new RuntimeException(createMessage(collapsedRequests, batchResponse));\n        }\n        int count = 0;\n        for (CollapsedRequest<Object, Object> request : collapsedRequests) {\n            request.setResponse(batchResponse.get(count++));\n        }\n    }\n\n    private String createMessage(Collection<CollapsedRequest<Object, Object>> requests,\n                                 List<Object> response) {\n        return ERROR_MSG + arrayFormat(ERROR_MSF_TEMPLATE, new Object[]{getCollapserKey().name(),\n                requests.size(), response.size()}).getMessage();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AbstractHystrixCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContext;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixCacheKeyGenerator;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixGeneratedCacheKey;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixRequestCacheManager;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\nimport javax.annotation.concurrent.ThreadSafe;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Base class for hystrix commands.\n *\n * @param <T> the return type\n */\n@ThreadSafe\npublic abstract class AbstractHystrixCommand<T> extends com.netflix.hystrix.HystrixCommand<T> {\n\n    private final CommandActions commandActions;\n    private final CacheInvocationContext<CacheResult> cacheResultInvocationContext;\n    private final CacheInvocationContext<CacheRemove> cacheRemoveInvocationContext;\n    private final Collection<HystrixCollapser.CollapsedRequest<Object, Object>> collapsedRequests;\n    private final List<Class<? extends Throwable>> ignoreExceptions;\n    private final ExecutionType executionType;\n    private final HystrixCacheKeyGenerator defaultCacheKeyGenerator = HystrixCacheKeyGenerator.getInstance();\n\n    protected AbstractHystrixCommand(HystrixCommandBuilder builder) {\n        super(builder.getSetterBuilder().build());\n        this.commandActions = builder.getCommandActions();\n        this.collapsedRequests = builder.getCollapsedRequests();\n        this.cacheResultInvocationContext = builder.getCacheResultInvocationContext();\n        this.cacheRemoveInvocationContext = builder.getCacheRemoveInvocationContext();\n        this.ignoreExceptions = builder.getIgnoreExceptions();\n        this.executionType = builder.getExecutionType();\n    }\n\n    /**\n     * Gets command action.\n     *\n     * @return command action\n     */\n    protected CommandAction getCommandAction() {\n        return commandActions.getCommandAction();\n    }\n\n    /**\n     * Gets fallback action.\n     *\n     * @return fallback action\n     */\n    protected CommandAction getFallbackAction() {\n        return commandActions.getFallbackAction();\n    }\n\n    /**\n     * Gets collapsed requests.\n     *\n     * @return collapsed requests\n     */\n    protected Collection<HystrixCollapser.CollapsedRequest<Object, Object>> getCollapsedRequests() {\n        return collapsedRequests;\n    }\n\n    /**\n     * Gets exceptions types which should be ignored.\n     *\n     * @return exceptions types\n     */\n    protected List<Class<? extends Throwable>> getIgnoreExceptions() {\n        return ignoreExceptions;\n    }\n\n    protected ExecutionType getExecutionType() {\n        return executionType;\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    protected String getCacheKey() {\n        String key = null;\n        if (cacheResultInvocationContext != null) {\n            HystrixGeneratedCacheKey hystrixGeneratedCacheKey =\n                    defaultCacheKeyGenerator.generateCacheKey(cacheResultInvocationContext);\n            key = hystrixGeneratedCacheKey.getCacheKey();\n        }\n        return key;\n    }\n\n    /**\n     * Check whether triggered exception is ignorable.\n     *\n     * @param throwable the exception occurred during a command execution\n     * @return true if exception is ignorable, otherwise - false\n     */\n    boolean isIgnorable(Throwable throwable) {\n        if (ignoreExceptions == null || ignoreExceptions.isEmpty()) {\n            return false;\n        }\n        for (Class<? extends Throwable> ignoreException : ignoreExceptions) {\n            if (ignoreException.isAssignableFrom(throwable.getClass())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Executes an action. If an action has failed and an exception is ignorable then propagate it as HystrixBadRequestException\n     * otherwise propagate original exception to trigger fallback method.\n     * Note: If an exception occurred in a command directly extends {@link java.lang.Throwable} then this exception cannot be re-thrown\n     * as original exception because HystrixCommand.run() allows throw subclasses of {@link java.lang.Exception}.\n     * Thus we need to wrap cause in RuntimeException, anyway in this case the fallback logic will be triggered.\n     *\n     * @param action the action\n     * @return result of command action execution\n     */\n    Object process(Action action) throws Exception {\n        Object result;\n        try {\n            result = action.execute();\n            flushCache();\n        } catch (CommandActionExecutionException throwable) {\n            Throwable cause = throwable.getCause();\n            if (isIgnorable(cause)) {\n                throw new HystrixBadRequestException(cause.getMessage(), cause);\n            }\n            if (cause instanceof RuntimeException) {\n                throw (RuntimeException) cause;\n            } else if (cause instanceof Exception) {\n                throw (Exception) cause;\n            } else {\n                // instance of Throwable\n                throw new CommandActionExecutionException(cause);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    protected abstract T run() throws Exception;\n\n    /**\n     * Clears cache for the specified hystrix command.\n     */\n    protected void flushCache() {\n        if (cacheRemoveInvocationContext != null) {\n            HystrixRequestCacheManager.getInstance().clearCache(cacheRemoveInvocationContext);\n        }\n    }\n\n    /**\n     * Common action.\n     */\n    abstract class Action {\n        /**\n         * Each implementation of this method should wrap any exceptions in CommandActionExecutionException.\n         *\n         * @return execution result\n         * @throws CommandActionExecutionException\n         */\n        abstract Object execute() throws CommandActionExecutionException;\n    }\n\n\n    /**\n     * Builder to create error message for failed fallback operation.\n     */\n    static class FallbackErrorMessageBuilder {\n        private StringBuilder builder = new StringBuilder(\"failed to process fallback\");\n\n        static FallbackErrorMessageBuilder create() {\n            return new FallbackErrorMessageBuilder();\n        }\n\n        public FallbackErrorMessageBuilder append(CommandAction action, Throwable throwable) {\n            return commandAction(action).exception(throwable);\n        }\n\n        private FallbackErrorMessageBuilder commandAction(CommandAction action) {\n            if (action instanceof CommandExecutionAction || action instanceof LazyCommandExecutionAction) {\n                builder.append(\": '\").append(action.getActionName()).append(\"'. \")\n                        .append(action.getActionName()).append(\" fallback is a hystrix command. \");\n            } else if (action instanceof MethodExecutionAction) {\n                builder.append(\" is the method: '\").append(action.getActionName()).append(\"'. \");\n            }\n            return this;\n        }\n\n        private FallbackErrorMessageBuilder exception(Throwable throwable) {\n            if (throwable instanceof HystrixBadRequestException) {\n                builder.append(\"exception: '\").append(throwable.getCause().getClass())\n                        .append(\"' occurred in fallback was ignored and wrapped to HystrixBadRequestException.\\n\");\n            } else if (throwable instanceof HystrixRuntimeException) {\n                builder.append(\"exception: '\").append(throwable.getCause().getClass())\n                        .append(\"' occurred in fallback wasn't ignored.\\n\");\n            }\n            return this;\n        }\n\n        public String build() {\n            return builder.toString();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AsyncResult.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Fake implementation of {@link Future}. Can be used for method signatures\n * which are declared with a Future return type for asynchronous execution.\n * Provides abstract {@link #invoke()} method to wrap some logic for an asynchronous call.\n *\n * @param <T> the type of result\n */\npublic abstract class AsyncResult<T> implements Future<T>, ClosureCommand<T> {\n\n    private static final String ERROR_MSG = \"AsyncResult is just a stub and cannot be used as complete implementation of Future\";\n\n    @Override\n    public boolean cancel(boolean mayInterruptIfRunning) throws UnsupportedOperationException {\n        throw new UnsupportedOperationException(ERROR_MSG);\n    }\n\n    @Override\n    public boolean isCancelled() throws UnsupportedOperationException {\n        throw new UnsupportedOperationException(ERROR_MSG);\n    }\n\n    @Override\n    public boolean isDone() throws UnsupportedOperationException {\n        throw new UnsupportedOperationException(ERROR_MSG);\n    }\n\n    @Override\n    public T get() throws UnsupportedOperationException {\n        throw new UnsupportedOperationException(ERROR_MSG);\n    }\n\n    @Override\n    public T get(long timeout, TimeUnit unit) throws UnsupportedOperationException {\n        throw new UnsupportedOperationException(ERROR_MSG);\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    public abstract T invoke();\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/BatchHystrixCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackInvocationException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.annotation.concurrent.ThreadSafe;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport static com.netflix.hystrix.contrib.javanica.exception.ExceptionUtils.unwrapCause;\nimport static com.netflix.hystrix.contrib.javanica.utils.CommonUtils.createArgsForFallback;\n\n/**\n * This command is used in collapser.\n */\n@ThreadSafe\npublic class BatchHystrixCommand extends AbstractHystrixCommand<List<Object>> {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(BatchHystrixCommand.class);\n\n    public BatchHystrixCommand(HystrixCommandBuilder builder) {\n        super(builder);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    protected List<Object> run() throws Exception {\n        Object[] args = toArgs(getCollapsedRequests());\n        return (List) process(args);\n    }\n\n    private Object process(final Object[] args) throws Exception {\n        return process(new Action() {\n            @Override\n            Object execute() {\n                return getCommandAction().executeWithArgs(getExecutionType(), args);\n            }\n        });\n    }\n\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    protected List<Object> getFallback() {\n        if (getFallbackAction() != null) {\n            final CommandAction commandAction = getFallbackAction();\n\n            try {\n                return (List<Object>) process(new Action() {\n                    @Override\n                    Object execute() {\n                        MetaHolder metaHolder = commandAction.getMetaHolder();\n                        Object[] args = toArgs(getCollapsedRequests());\n                        args = createArgsForFallback(args, metaHolder, getExecutionException());\n                        return commandAction.executeWithArgs(commandAction.getMetaHolder().getFallbackExecutionType(), args);\n                    }\n                });\n            } catch (Throwable e) {\n                LOGGER.error(FallbackErrorMessageBuilder.create()\n                        .append(commandAction, e).build());\n                throw new FallbackInvocationException(unwrapCause(e));\n            }\n        } else {\n            return super.getFallback();\n        }\n\n    }\n\n    private Object[] toArgs(Collection<HystrixCollapser.CollapsedRequest<Object, Object>> requests) {\n        return new Object[]{collect(requests)};\n    }\n\n    private List<Object> collect(Collection<HystrixCollapser.CollapsedRequest<Object, Object>> requests) {\n        List<Object> commandArgs = new ArrayList<Object>();\n        for (HystrixCollapser.CollapsedRequest<Object, Object> request : requests) {\n            final Object[] args = (Object[]) request.getArgument();\n            commandArgs.add(args[0]);\n        }\n        return commandArgs;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/ClosureCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n/**\n * This interface is used to perform command logic within an anonymous class and basically used as wrapper for some logic.\n *\n * @param <T> command result type\n */\npublic interface ClosureCommand<T> {\n\n    /**\n     * Process logic.\n     *\n     * @return result\n     */\n    T invoke();\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandAction.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\n\n/**\n * Simple action to encapsulate some logic to process it in a Hystrix command.\n */\npublic interface CommandAction {\n\n    MetaHolder getMetaHolder();\n\n    /**\n     * Executes action in accordance with the given execution type.\n     *\n     * @param executionType the execution type\n     * @return result of execution\n     * @throws com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException\n     */\n    Object execute(ExecutionType executionType) throws CommandActionExecutionException;\n\n    /**\n     * Executes action with parameters in accordance with the given execution ty\n     *\n     * @param executionType the execution type\n     * @param args          the parameters of the action\n     * @return result of execution\n     * @throws com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException\n     */\n    Object executeWithArgs(ExecutionType executionType, Object[] args) throws CommandActionExecutionException;\n\n    /**\n     * Gets action name. Useful for debugging.\n     *\n     * @return the action name\n     */\n    String getActionName();\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandActions.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n/**\n * Wrapper for command actions combines different actions together.\n *\n * @author dmgcodevil\n */\npublic class CommandActions {\n\n    private final CommandAction commandAction;\n    private final CommandAction fallbackAction;\n\n    public CommandActions(Builder builder) {\n        this.commandAction = builder.commandAction;\n        this.fallbackAction = builder.fallbackAction;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public CommandAction getCommandAction() {\n        return commandAction;\n    }\n\n    public CommandAction getFallbackAction() {\n        return fallbackAction;\n    }\n\n    public boolean hasFallbackAction() {\n        return fallbackAction != null;\n    }\n\n    public static class Builder {\n        private CommandAction commandAction;\n        private CommandAction fallbackAction;\n\n        public Builder commandAction(CommandAction pCommandAction) {\n            this.commandAction = pCommandAction;\n            return this;\n        }\n\n        public Builder fallbackAction(CommandAction pFallbackAction) {\n            this.fallbackAction = pFallbackAction;\n            return this;\n        }\n\n        public CommandActions build() {\n            return new CommandActions(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandExecutionAction.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\n\n/**\n * Action to execute a Hystrix command.\n */\npublic class CommandExecutionAction implements CommandAction {\n\n    private HystrixInvokable hystrixCommand;\n    private MetaHolder metaHolder;\n\n    /**\n     * Constructor with parameters.\n     *\n     * @param hystrixCommand the hystrix command to execute.\n     */\n    public CommandExecutionAction(HystrixInvokable hystrixCommand, MetaHolder metaHolder) {\n        this.hystrixCommand = hystrixCommand;\n        this.metaHolder = metaHolder;\n    }\n\n    @Override\n    public MetaHolder getMetaHolder() {\n        return metaHolder;\n    }\n\n    @Override\n    public Object execute(ExecutionType executionType) throws CommandActionExecutionException {\n        return CommandExecutor.execute(hystrixCommand, executionType, metaHolder);\n    }\n\n    @Override\n    public Object executeWithArgs(ExecutionType executionType, Object[] args) throws CommandActionExecutionException {\n        return CommandExecutor.execute(hystrixCommand, executionType, metaHolder);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String getActionName() {\n        if (hystrixCommand != null && hystrixCommand instanceof HystrixInvokableInfo) {\n            HystrixInvokableInfo info = (HystrixInvokableInfo) hystrixCommand;\n            return info.getCommandKey().name();\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/CommandExecutor.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.HystrixExecutable;\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.HystrixObservable;\nimport com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode;\nimport com.netflix.hystrix.contrib.javanica.utils.FutureDecorator;\nimport org.apache.commons.lang3.Validate;\n\n/**\n * Invokes necessary method of {@link HystrixExecutable} or {@link HystrixObservable} for specified execution type:\n * <p/>\n * {@link ExecutionType#SYNCHRONOUS} -> {@link com.netflix.hystrix.HystrixExecutable#execute()}\n * <p/>\n * {@link ExecutionType#ASYNCHRONOUS} -> {@link com.netflix.hystrix.HystrixExecutable#queue()}\n * <p/>\n * {@link ExecutionType#OBSERVABLE} -> depends on specify observable execution mode:\n * {@link ObservableExecutionMode#EAGER} - {@link HystrixObservable#observe()},\n * {@link ObservableExecutionMode#LAZY} -  {@link HystrixObservable#toObservable()}.\n */\npublic class CommandExecutor {\n\n    /**\n     * Calls a method of {@link HystrixExecutable} in accordance with specified execution type.\n     *\n     * @param invokable  {@link HystrixInvokable}\n     * @param metaHolder {@link MetaHolder}\n     * @return the result of invocation of specific method.\n     * @throws RuntimeException\n     */\n    public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {\n        Validate.notNull(invokable);\n        Validate.notNull(metaHolder);\n\n        switch (executionType) {\n            case SYNCHRONOUS: {\n                return castToExecutable(invokable, executionType).execute();\n            }\n            case ASYNCHRONOUS: {\n                HystrixExecutable executable = castToExecutable(invokable, executionType);\n                if (metaHolder.hasFallbackMethodCommand()\n                        && ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {\n                    return new FutureDecorator(executable.queue());\n                }\n                return executable.queue();\n            }\n            case OBSERVABLE: {\n                HystrixObservable observable = castToObservable(invokable);\n                return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();\n            }\n            default:\n                throw new RuntimeException(\"unsupported execution type: \" + executionType);\n        }\n    }\n\n    private static HystrixExecutable castToExecutable(HystrixInvokable invokable, ExecutionType executionType) {\n        if (invokable instanceof HystrixExecutable) {\n            return (HystrixExecutable) invokable;\n        }\n        throw new RuntimeException(\"Command should implement \" + HystrixExecutable.class.getCanonicalName() + \" interface to execute in: \" + executionType + \" mode\");\n    }\n\n    private static HystrixObservable castToObservable(HystrixInvokable invokable) {\n        if (invokable instanceof HystrixObservable) {\n            return (HystrixObservable) invokable;\n        }\n        throw new RuntimeException(\"Command should implement \" + HystrixObservable.class.getCanonicalName() + \" interface to execute in observable mode\");\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/ExecutionType.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.google.common.collect.ImmutableSet;\nimport rx.Completable;\nimport rx.Observable;\nimport rx.Single;\n\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\n/**\n * Specifies executions types.\n */\npublic enum ExecutionType {\n\n    /**\n     * Used for asynchronous execution of command.\n     */\n    ASYNCHRONOUS,\n\n    /**\n     * Used for synchronous execution of command.\n     */\n    SYNCHRONOUS,\n\n    /**\n     * Reactive execution (asynchronous callback).\n     */\n    OBSERVABLE;\n\n    // RX types\n    private static final Set<? extends Class> RX_TYPES = ImmutableSet.of(Observable.class, Single.class, Completable.class);\n\n    /**\n     * Gets execution type for specified class type.\n     * @param type the type\n     * @return the execution type {@link ExecutionType}\n     */\n    public static ExecutionType getExecutionType(Class<?> type) {\n        if (Future.class.isAssignableFrom(type)) {\n            return ExecutionType.ASYNCHRONOUS;\n        } else if (isRxType(type)) {\n            return ExecutionType.OBSERVABLE;\n        } else {\n            return ExecutionType.SYNCHRONOUS;\n        }\n    }\n\n    private static boolean isRxType(Class<?> cl) {\n        for (Class<?> rxType : RX_TYPES) {\n            if (rxType.isAssignableFrom(cl)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackInvocationException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.annotation.concurrent.ThreadSafe;\n\nimport static com.netflix.hystrix.contrib.javanica.exception.ExceptionUtils.unwrapCause;\nimport static com.netflix.hystrix.contrib.javanica.utils.CommonUtils.createArgsForFallback;\n\n/**\n * Implementation of AbstractHystrixCommand which returns an Object as result.\n */\n@ThreadSafe\npublic class GenericCommand extends AbstractHystrixCommand<Object> {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(GenericCommand.class);\n\n    public GenericCommand(HystrixCommandBuilder builder) {\n        super(builder);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Object run() throws Exception {\n        LOGGER.debug(\"execute command: {}\", getCommandKey().name());\n        return process(new Action() {\n            @Override\n            Object execute() {\n                return getCommandAction().execute(getExecutionType());\n            }\n        });\n    }\n\n    /**\n     * The fallback is performed whenever a command execution fails.\n     * Also a fallback method will be invoked within separate command in the case if fallback method was annotated with\n     * HystrixCommand annotation, otherwise current implementation throws RuntimeException and leaves the caller to deal with it\n     * (see {@link super#getFallback()}).\n     * The getFallback() is always processed synchronously.\n     * Since getFallback() can throw only runtime exceptions thus any exceptions are thrown within getFallback() method\n     * are wrapped in {@link FallbackInvocationException}.\n     * A caller gets {@link com.netflix.hystrix.exception.HystrixRuntimeException}\n     * and should call getCause to get original exception that was thrown in getFallback().\n     *\n     * @return result of invocation of fallback method or RuntimeException\n     */\n    @Override\n    protected Object getFallback() {\n        final CommandAction commandAction = getFallbackAction();\n        if (commandAction != null) {\n            try {\n                return process(new Action() {\n                    @Override\n                    Object execute() {\n                        MetaHolder metaHolder = commandAction.getMetaHolder();\n                        Object[] args = createArgsForFallback(metaHolder, getExecutionException());\n                        return commandAction.executeWithArgs(metaHolder.getFallbackExecutionType(), args);\n                    }\n                });\n            } catch (Throwable e) {\n                LOGGER.error(FallbackErrorMessageBuilder.create()\n                        .append(commandAction, e).build());\n                throw new FallbackInvocationException(unwrapCause(e));\n            }\n        } else {\n            return super.getFallback();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericObservableCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContext;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixCacheKeyGenerator;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixGeneratedCacheKey;\nimport com.netflix.hystrix.contrib.javanica.cache.HystrixRequestCacheManager;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackInvocationException;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Completable;\nimport rx.Observable;\nimport rx.Single;\nimport rx.functions.Func1;\n\nimport javax.annotation.concurrent.ThreadSafe;\nimport java.util.List;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.CommonUtils.createArgsForFallback;\n\n/**\n * Generic class for all observable commands executed within javanica context.\n */\n@ThreadSafe\npublic class GenericObservableCommand extends HystrixObservableCommand {\n\n    private final CommandActions commandActions;\n    private final CacheInvocationContext<CacheResult> cacheResultInvocationContext;\n    private final CacheInvocationContext<CacheRemove> cacheRemoveInvocationContext;\n    private final List<Class<? extends Throwable>> ignoreExceptions;\n    private final ExecutionType executionType;\n    private final HystrixCacheKeyGenerator defaultCacheKeyGenerator = HystrixCacheKeyGenerator.getInstance();\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(GenericObservableCommand.class);\n\n    public GenericObservableCommand(HystrixCommandBuilder builder) {\n        super(builder.getSetterBuilder().buildObservableCommandSetter());\n        this.commandActions = builder.getCommandActions();\n        this.cacheResultInvocationContext = builder.getCacheResultInvocationContext();\n        this.cacheRemoveInvocationContext = builder.getCacheRemoveInvocationContext();\n        this.ignoreExceptions = builder.getIgnoreExceptions();\n        this.executionType = builder.getExecutionType();\n    }\n\n    /**\n     *{@inheritDoc}.\n     */\n    @Override\n    protected Observable construct() {\n        Observable result;\n        try {\n            Observable observable = toObservable(commandActions.getCommandAction().execute(executionType));\n            result = observable\n                    .onErrorResumeNext(new Func1<Throwable, Observable>() {\n                        @Override\n                        public Observable call(Throwable throwable) {\n                            if (isIgnorable(throwable)) {\n                                return Observable.error(new HystrixBadRequestException(throwable.getMessage(), throwable));\n                            }\n                            return Observable.error(throwable);\n                        }\n                    });\n            flushCache();\n        } catch (CommandActionExecutionException throwable) {\n            Throwable cause = throwable.getCause();\n            if (isIgnorable(cause)) {\n                throw new HystrixBadRequestException(cause.getMessage(), cause);\n            }\n            throw throwable;\n        }\n        return result;\n    }\n\n    /**\n     *{@inheritDoc}.\n     */\n    @Override\n    protected Observable resumeWithFallback() {\n        if (commandActions.hasFallbackAction()) {\n            MetaHolder metaHolder = commandActions.getFallbackAction().getMetaHolder();\n            Throwable cause = getExecutionException();\n            if (cause instanceof CommandActionExecutionException) {\n                cause = cause.getCause();\n            }\n\n            Object[] args = createArgsForFallback(metaHolder, cause);\n            try {\n                Object res = commandActions.getFallbackAction().executeWithArgs(executionType, args);\n                if (res instanceof Observable) {\n                    return (Observable) res;\n                } else if (res instanceof Single) {\n                    return ((Single) res).toObservable();\n                } else if (res instanceof Completable) {\n                    return ((Completable) res).toObservable();\n                } else {\n                    return Observable.just(res);\n                }\n            } catch (Exception e) {\n                LOGGER.error(AbstractHystrixCommand.FallbackErrorMessageBuilder.create()\n                        .append(commandActions.getFallbackAction(), e).build());\n                throw new FallbackInvocationException(e.getCause());\n            }\n        }\n        return super.resumeWithFallback();\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    protected String getCacheKey() {\n        String key = null;\n        if (cacheResultInvocationContext != null) {\n            HystrixGeneratedCacheKey hystrixGeneratedCacheKey =\n                    defaultCacheKeyGenerator.generateCacheKey(cacheResultInvocationContext);\n            key = hystrixGeneratedCacheKey.getCacheKey();\n        }\n        return key;\n    }\n\n    /**\n     * Clears cache for the specified hystrix command.\n     */\n    protected void flushCache() {\n        if (cacheRemoveInvocationContext != null) {\n            HystrixRequestCacheManager.getInstance().clearCache(cacheRemoveInvocationContext);\n        }\n    }\n\n    /**\n     * Check whether triggered exception is ignorable.\n     *\n     * @param throwable the exception occurred during a command execution\n     * @return true if exception is ignorable, otherwise - false\n     */\n    boolean isIgnorable(Throwable throwable) {\n        if (ignoreExceptions == null || ignoreExceptions.isEmpty()) {\n            return false;\n        }\n        for (Class<? extends Throwable> ignoreException : ignoreExceptions) {\n            if (ignoreException.isAssignableFrom(throwable.getClass())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private Observable toObservable(Object obj) {\n        if (Observable.class.isAssignableFrom(obj.getClass())) {\n            return (Observable) obj;\n        } else if (Completable.class.isAssignableFrom(obj.getClass())) {\n            return ((Completable) obj).toObservable();\n        } else if (Single.class.isAssignableFrom(obj.getClass())) {\n            return ((Single) obj).toObservable();\n        } else {\n            throw new IllegalStateException(\"unsupported rx type: \" + obj.getClass());\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericSetterBuilder.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;\nimport com.netflix.hystrix.contrib.javanica.exception.HystrixPropertyException;\nimport org.apache.commons.lang3.StringUtils;\n\nimport javax.annotation.concurrent.Immutable;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.initializeCollapserProperties;\n\n/**\n * Builder for Hystrix Setters: {@link HystrixCommand.Setter}, {@link HystrixObservableCommand.Setter}, {@link HystrixCollapser.Setter}.\n */\n@Immutable\npublic class GenericSetterBuilder {\n\n    private String groupKey;\n    private String commandKey;\n    private String threadPoolKey;\n    private String collapserKey;\n    private HystrixCollapser.Scope scope;\n    private List<HystrixProperty> commandProperties = Collections.emptyList();\n    private List<HystrixProperty> collapserProperties = Collections.emptyList();\n    private List<HystrixProperty> threadPoolProperties = Collections.emptyList();\n\n    public GenericSetterBuilder(Builder builder) {\n        this.groupKey = builder.groupKey;\n        this.commandKey = builder.commandKey;\n        this.threadPoolKey = builder.threadPoolKey;\n        this.collapserKey = builder.collapserKey;\n        this.scope = builder.scope;\n        this.commandProperties = builder.commandProperties;\n        this.collapserProperties = builder.collapserProperties;\n        this.threadPoolProperties = builder.threadPoolProperties;\n    }\n\n    public static Builder builder(){\n        return new Builder();\n    }\n\n\n    /**\n     * Creates instance of {@link HystrixCommand.Setter}.\n     *\n     * @return the instance of {@link HystrixCommand.Setter}\n     */\n    public HystrixCommand.Setter build() throws HystrixPropertyException {\n        HystrixCommand.Setter setter = HystrixCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));\n        if (StringUtils.isNotBlank(threadPoolKey)) {\n            setter.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey));\n        }\n        try {\n            setter.andThreadPoolPropertiesDefaults(HystrixPropertiesManager.initializeThreadPoolProperties(threadPoolProperties));\n        } catch (IllegalArgumentException e) {\n            throw new HystrixPropertyException(\"Failed to set Thread Pool properties. \" + getInfo(), e);\n        }\n        try {\n            setter.andCommandPropertiesDefaults(HystrixPropertiesManager.initializeCommandProperties(commandProperties));\n        } catch (IllegalArgumentException e) {\n            throw new HystrixPropertyException(\"Failed to set Command properties. \" + getInfo(), e);\n        }\n        return setter;\n    }\n\n    // todo dmgcodevil: it would be better to reuse the code from build() method\n    public HystrixObservableCommand.Setter buildObservableCommandSetter() {\n        HystrixObservableCommand.Setter setter = HystrixObservableCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));\n        try {\n            setter.andCommandPropertiesDefaults(HystrixPropertiesManager.initializeCommandProperties(commandProperties));\n        } catch (IllegalArgumentException e) {\n            throw new HystrixPropertyException(\"Failed to set Command properties. \" + getInfo(), e);\n        }\n        return setter;\n    }\n\n    public HystrixCollapser.Setter buildCollapserCommandSetter(){\n        HystrixCollapserProperties.Setter propSetter = initializeCollapserProperties(collapserProperties);\n        return HystrixCollapser.Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey(collapserKey)).andScope(scope)\n                .andCollapserPropertiesDefaults(propSetter);\n    }\n\n    private String getInfo() {\n        return \"groupKey: '\" + groupKey + \"', commandKey: '\" + commandKey + \"', threadPoolKey: '\" + threadPoolKey + \"'\";\n    }\n\n\n    public static class Builder {\n        private String groupKey;\n        private String commandKey;\n        private String threadPoolKey;\n        private String collapserKey;\n        private HystrixCollapser.Scope scope;\n        private List<HystrixProperty> commandProperties = Collections.emptyList();\n        private List<HystrixProperty> collapserProperties = Collections.emptyList();\n        private List<HystrixProperty> threadPoolProperties = Collections.emptyList();\n\n        public Builder groupKey(String pGroupKey) {\n            this.groupKey = pGroupKey;\n            return this;\n        }\n\n        public Builder groupKey(String pGroupKey, String def) {\n            this.groupKey = StringUtils.isNotEmpty(pGroupKey) ? pGroupKey : def;\n            return this;\n        }\n\n        public Builder commandKey(String pCommandKey) {\n            this.commandKey = pCommandKey;\n            return this;\n        }\n\n        @Deprecated\n        public Builder commandKey(String pCommandKey, String def) {\n            this.commandKey = StringUtils.isNotEmpty(pCommandKey) ? pCommandKey : def;\n            return this;\n        }\n\n        public Builder collapserKey(String pCollapserKey) {\n            this.collapserKey = pCollapserKey;\n            return this;\n        }\n\n        public Builder scope(HystrixCollapser.Scope pScope) {\n            this.scope = pScope;\n            return this;\n        }\n\n        public Builder collapserProperties(List<HystrixProperty> properties) {\n            collapserProperties = properties;\n            return this;\n        }\n\n        public Builder commandProperties(List<HystrixProperty> properties) {\n            commandProperties = properties;\n            return this;\n        }\n\n\n        public Builder threadPoolProperties(List<HystrixProperty> properties) {\n            threadPoolProperties = properties;\n            return this;\n        }\n\n        public Builder threadPoolKey(String pThreadPoolKey) {\n            this.threadPoolKey = pThreadPoolKey;\n            return this;\n        }\n\n        public GenericSetterBuilder build(){\n            return new GenericSetterBuilder(this);\n        }\n\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/HystrixCommandBuilder.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.google.common.collect.ImmutableList;\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContext;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\n\nimport javax.annotation.concurrent.Immutable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Builder contains all necessary information required to create specific hystrix command.\n *\n * @author dmgcodevil\n */\n@Immutable\npublic class HystrixCommandBuilder {\n\n    private final GenericSetterBuilder setterBuilder;\n    private final CommandActions commandActions;\n    private final CacheInvocationContext<CacheResult> cacheResultInvocationContext;\n    private final CacheInvocationContext<CacheRemove> cacheRemoveInvocationContext;\n    private final Collection<HystrixCollapser.CollapsedRequest<Object, Object>> collapsedRequests;\n    private final List<Class<? extends Throwable>> ignoreExceptions;\n    private final ExecutionType executionType;\n\n    public HystrixCommandBuilder(Builder builder) {\n        this.setterBuilder = builder.setterBuilder;\n        this.commandActions = builder.commandActions;\n        this.cacheResultInvocationContext = builder.cacheResultInvocationContext;\n        this.cacheRemoveInvocationContext = builder.cacheRemoveInvocationContext;\n        this.collapsedRequests = builder.collapsedRequests;\n        this.ignoreExceptions = builder.ignoreExceptions;\n        this.executionType = builder.executionType;\n    }\n\n    public static <ResponseType> Builder builder() {\n        return new Builder<ResponseType>();\n    }\n\n    public GenericSetterBuilder getSetterBuilder() {\n        return setterBuilder;\n    }\n\n    public CommandActions getCommandActions() {\n        return commandActions;\n    }\n\n    public CacheInvocationContext<CacheResult> getCacheResultInvocationContext() {\n        return cacheResultInvocationContext;\n    }\n\n    public CacheInvocationContext<CacheRemove> getCacheRemoveInvocationContext() {\n        return cacheRemoveInvocationContext;\n    }\n\n    public Collection<HystrixCollapser.CollapsedRequest<Object, Object>> getCollapsedRequests() {\n        return collapsedRequests;\n    }\n\n    public List<Class<? extends Throwable>> getIgnoreExceptions() {\n        return ignoreExceptions;\n    }\n\n    public ExecutionType getExecutionType() {\n        return executionType;\n    }\n\n\n    public static class Builder<ResponseType> {\n        private GenericSetterBuilder setterBuilder;\n        private CommandActions commandActions;\n        private CacheInvocationContext<CacheResult> cacheResultInvocationContext;\n        private CacheInvocationContext<CacheRemove> cacheRemoveInvocationContext;\n        private Collection<HystrixCollapser.CollapsedRequest<ResponseType, Object>> collapsedRequests = Collections.emptyList();\n        private List<Class<? extends Throwable>> ignoreExceptions = Collections.emptyList();\n        private ExecutionType executionType = ExecutionType.SYNCHRONOUS;\n\n        /**\n         * Sets the builder to create specific Hystrix setter, for instance HystrixCommand.Setter\n         *\n         * @param pSetterBuilder the builder to create specific Hystrix setter\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder setterBuilder(GenericSetterBuilder pSetterBuilder) {\n            this.setterBuilder = pSetterBuilder;\n            return this;\n        }\n\n        /**\n         * Sets command actions {@link CommandActions}.\n         *\n         * @param pCommandActions the command actions\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder commandActions(CommandActions pCommandActions) {\n            this.commandActions = pCommandActions;\n            return this;\n        }\n\n        /**\n         * Sets CacheResult invocation context, see {@link CacheInvocationContext} and {@link CacheResult}.\n         *\n         * @param pCacheResultInvocationContext the CacheResult invocation context\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder cacheResultInvocationContext(CacheInvocationContext<CacheResult> pCacheResultInvocationContext) {\n            this.cacheResultInvocationContext = pCacheResultInvocationContext;\n            return this;\n        }\n\n        /**\n         * Sets CacheRemove invocation context, see {@link CacheInvocationContext} and {@link CacheRemove}.\n         *\n         * @param pCacheRemoveInvocationContext the CacheRemove invocation context\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder cacheRemoveInvocationContext(CacheInvocationContext<CacheRemove> pCacheRemoveInvocationContext) {\n            this.cacheRemoveInvocationContext = pCacheRemoveInvocationContext;\n            return this;\n        }\n\n        /**\n         * Sets collapsed requests.\n         *\n         * @param pCollapsedRequests the collapsed requests\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder collapsedRequests(Collection<HystrixCollapser.CollapsedRequest<ResponseType, Object>> pCollapsedRequests) {\n            this.collapsedRequests = pCollapsedRequests;\n            return this;\n        }\n\n        /**\n         * Sets exceptions that should be ignored and wrapped to throw in {@link com.netflix.hystrix.exception.HystrixBadRequestException}.\n         *\n         * @param pIgnoreExceptions the exceptions to be ignored\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder ignoreExceptions(List<Class<? extends Throwable>> pIgnoreExceptions) {\n            this.ignoreExceptions = ImmutableList.copyOf(pIgnoreExceptions);\n            return this;\n        }\n\n        /**\n         * Sets execution type, see {@link ExecutionType}.\n         *\n         * @param pExecutionType the execution type\n         * @return this {@link HystrixCommandBuilder.Builder}\n         */\n        public Builder executionType(ExecutionType pExecutionType) {\n            this.executionType = pExecutionType;\n            return this;\n        }\n\n        /**\n         * Creates new {@link HystrixCommandBuilder} instance.\n         *\n         * @return new {@link HystrixCommandBuilder} instance\n         */\n        public HystrixCommandBuilder build() {\n            return new HystrixCommandBuilder(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/HystrixCommandBuilderFactory.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.utils.FallbackMethod;\nimport com.netflix.hystrix.contrib.javanica.utils.MethodProvider;\nimport org.apache.commons.lang3.Validate;\n\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport static com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContextFactory.createCacheRemoveInvocationContext;\nimport static com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContextFactory.createCacheResultInvocationContext;\nimport static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;\nimport static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.getAjcMethodAroundAdvice;\n\n/**\n * Created by dmgcodevil.\n */\npublic class HystrixCommandBuilderFactory {\n\n    // todo Add Cache\n\n    private static final HystrixCommandBuilderFactory INSTANCE = new HystrixCommandBuilderFactory();\n\n    public static HystrixCommandBuilderFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private HystrixCommandBuilderFactory() {\n\n    }\n\n    public HystrixCommandBuilder create(MetaHolder metaHolder) {\n        return create(metaHolder, Collections.<HystrixCollapser.CollapsedRequest<Object, Object>>emptyList());\n    }\n\n    public <ResponseType> HystrixCommandBuilder create(MetaHolder metaHolder, Collection<HystrixCollapser.CollapsedRequest<ResponseType, Object>> collapsedRequests) {\n        validateMetaHolder(metaHolder);\n\n        return HystrixCommandBuilder.builder()\n                .setterBuilder(createGenericSetterBuilder(metaHolder))\n                .commandActions(createCommandActions(metaHolder))\n                .collapsedRequests(collapsedRequests)\n                .cacheResultInvocationContext(createCacheResultInvocationContext(metaHolder))\n                .cacheRemoveInvocationContext(createCacheRemoveInvocationContext(metaHolder))\n                .ignoreExceptions(metaHolder.getCommandIgnoreExceptions())\n                .executionType(metaHolder.getExecutionType())\n                .build();\n    }\n\n    private void validateMetaHolder(MetaHolder metaHolder) {\n        Validate.notNull(metaHolder, \"metaHolder is required parameter and cannot be null\");\n        Validate.isTrue(metaHolder.isCommandAnnotationPresent(), \"hystrixCommand annotation is absent\");\n    }\n\n    private GenericSetterBuilder createGenericSetterBuilder(MetaHolder metaHolder) {\n        GenericSetterBuilder.Builder setterBuilder = GenericSetterBuilder.builder()\n                .groupKey(metaHolder.getCommandGroupKey())\n                .threadPoolKey(metaHolder.getThreadPoolKey())\n                .commandKey(metaHolder.getCommandKey())\n                .collapserKey(metaHolder.getCollapserKey())\n                .commandProperties(metaHolder.getCommandProperties())\n                .threadPoolProperties(metaHolder.getThreadPoolProperties())\n                .collapserProperties(metaHolder.getCollapserProperties());\n        if (metaHolder.isCollapserAnnotationPresent()) {\n            setterBuilder.scope(metaHolder.getHystrixCollapser().scope());\n        }\n        return setterBuilder.build();\n    }\n\n    private CommandActions createCommandActions(MetaHolder metaHolder) {\n        CommandAction commandAction = createCommandAction(metaHolder);\n        CommandAction fallbackAction = createFallbackAction(metaHolder);\n        return CommandActions.builder().commandAction(commandAction)\n                .fallbackAction(fallbackAction).build();\n    }\n\n    private CommandAction createCommandAction(MetaHolder metaHolder) {\n        return new MethodExecutionAction(metaHolder.getObj(), metaHolder.getMethod(), metaHolder.getArgs(), metaHolder);\n    }\n\n    private CommandAction createFallbackAction(MetaHolder metaHolder) {\n\n        FallbackMethod fallbackMethod = MethodProvider.getInstance().getFallbackMethod(metaHolder.getObj().getClass(),\n                metaHolder.getMethod(), metaHolder.isExtendedFallback());\n        fallbackMethod.validateReturnType(metaHolder.getMethod());\n        CommandAction fallbackAction = null;\n        if (fallbackMethod.isPresent()) {\n\n            Method fMethod = fallbackMethod.getMethod();\n            Object[] args = fallbackMethod.isDefault() ? new Object[0] : metaHolder.getArgs();\n            if (fallbackMethod.isCommand()) {\n                fMethod.setAccessible(true);\n                HystrixCommand hystrixCommand = fMethod.getAnnotation(HystrixCommand.class);\n                MetaHolder fmMetaHolder = MetaHolder.builder()\n                        .obj(metaHolder.getObj())\n                        .method(fMethod)\n                        .ajcMethod(getAjcMethod(metaHolder.getObj(), fMethod))\n                        .args(args)\n                        .fallback(true)\n                        .defaultFallback(fallbackMethod.isDefault())\n                        .defaultCollapserKey(metaHolder.getDefaultCollapserKey())\n                        .fallbackMethod(fMethod)\n                        .extendedFallback(fallbackMethod.isExtended())\n                        .fallbackExecutionType(fallbackMethod.getExecutionType())\n                        .extendedParentFallback(metaHolder.isExtendedFallback())\n                        .observable(ExecutionType.OBSERVABLE == fallbackMethod.getExecutionType())\n                        .defaultCommandKey(fMethod.getName())\n                        .defaultGroupKey(metaHolder.getDefaultGroupKey())\n                        .defaultThreadPoolKey(metaHolder.getDefaultThreadPoolKey())\n                        .defaultProperties(metaHolder.getDefaultProperties().orNull())\n                        .hystrixCollapser(metaHolder.getHystrixCollapser())\n                        .observableExecutionMode(hystrixCommand.observableExecutionMode())\n                        .hystrixCommand(hystrixCommand).build();\n                fallbackAction = new LazyCommandExecutionAction(fmMetaHolder);\n            } else {\n                MetaHolder fmMetaHolder = MetaHolder.builder()\n                        .obj(metaHolder.getObj())\n                        .defaultFallback(fallbackMethod.isDefault())\n                        .method(fMethod)\n                        .fallbackExecutionType(ExecutionType.SYNCHRONOUS)\n                        .extendedFallback(fallbackMethod.isExtended())\n                        .extendedParentFallback(metaHolder.isExtendedFallback())\n                        .ajcMethod(null) // if fallback method isn't annotated with command annotation then we don't need to get ajc method for this\n                        .args(args).build();\n\n                fallbackAction = new MethodExecutionAction(fmMetaHolder.getObj(), fMethod, fmMetaHolder.getArgs(), fmMetaHolder);\n            }\n\n        }\n        return fallbackAction;\n    }\n\n    private Method getAjcMethod(Object target, Method fallback) {\n        if (isCompileWeaving()) {\n            return getAjcMethodAroundAdvice(target.getClass(), fallback);\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/HystrixCommandFactory.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.contrib.javanica.collapser.CommandCollapser;\n\n/**\n * Created by dmgcodevil.\n */\npublic class HystrixCommandFactory {\n\n    private static final HystrixCommandFactory INSTANCE = new HystrixCommandFactory();\n\n    private HystrixCommandFactory() {\n\n    }\n\n    public static HystrixCommandFactory getInstance() {\n        return INSTANCE;\n    }\n\n    public HystrixInvokable create(MetaHolder metaHolder) {\n        HystrixInvokable executable;\n        if (metaHolder.isCollapserAnnotationPresent()) {\n            executable = new CommandCollapser(metaHolder);\n        } else if (metaHolder.isObservable()) {\n            executable = new GenericObservableCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));\n        } else {\n            executable = new GenericCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));\n        }\n        return executable;\n    }\n\n    public HystrixInvokable createDelayed(MetaHolder metaHolder) {\n        HystrixInvokable executable;\n        if (metaHolder.isObservable()) {\n            executable = new GenericObservableCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));\n        } else {\n            executable = new GenericCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));\n        }\n        return executable;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/LazyCommandExecutionAction.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * This action creates related hystrix commands on demand when command creation can be postponed.\n */\npublic class LazyCommandExecutionAction implements CommandAction {\n\n    private MetaHolder originalMetaHolder;\n\n\n    public LazyCommandExecutionAction(MetaHolder metaHolder) {\n        this.originalMetaHolder = metaHolder;\n    }\n\n    @Override\n    public MetaHolder getMetaHolder() {\n        return originalMetaHolder;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Object execute(ExecutionType executionType) throws CommandActionExecutionException {\n        HystrixInvokable command = HystrixCommandFactory.getInstance().createDelayed(createCopy(originalMetaHolder, executionType));\n        return new CommandExecutionAction(command, originalMetaHolder).execute(executionType);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Object executeWithArgs(ExecutionType executionType, Object[] args) throws CommandActionExecutionException {\n        HystrixInvokable command = HystrixCommandFactory.getInstance().createDelayed(createCopy(originalMetaHolder, executionType, args));\n        return new CommandExecutionAction(command, originalMetaHolder).execute(executionType);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String getActionName() {\n        return StringUtils.isNotEmpty(originalMetaHolder.getHystrixCommand().commandKey()) ?\n                originalMetaHolder.getHystrixCommand().commandKey()\n                : originalMetaHolder.getDefaultCommandKey();\n    }\n\n    // todo dmgcodevil: move it to MetaHolder class ?\n    private MetaHolder createCopy(MetaHolder source, ExecutionType executionType) {\n        return MetaHolder.builder()\n                .obj(source.getObj())\n                .method(source.getMethod())\n                .ajcMethod(source.getAjcMethod())\n                .fallbackExecutionType(source.getFallbackExecutionType())\n                .extendedFallback(source.isExtendedFallback())\n                .extendedParentFallback(source.isExtendedParentFallback())\n                .executionType(executionType)\n                .args(source.getArgs())\n                .observable(source.isObservable())\n                .observableExecutionMode(source.getObservableExecutionMode())\n                .defaultCollapserKey(source.getDefaultCollapserKey())\n                .defaultCommandKey(source.getDefaultCommandKey())\n                .defaultGroupKey(source.getDefaultGroupKey())\n                .defaultThreadPoolKey(source.getDefaultThreadPoolKey())\n                .defaultProperties(source.getDefaultProperties().orNull())\n                .hystrixCollapser(source.getHystrixCollapser())\n                .hystrixCommand(source.getHystrixCommand()).build();\n    }\n\n    private MetaHolder createCopy(MetaHolder source, ExecutionType executionType, Object[] args) {\n        return MetaHolder.builder()\n                .obj(source.getObj())\n                .method(source.getMethod())\n                .executionType(executionType)\n                .ajcMethod(source.getAjcMethod())\n                .fallbackExecutionType(source.getFallbackExecutionType())\n                .extendedParentFallback(source.isExtendedParentFallback())\n                .extendedFallback(source.isExtendedFallback())\n                .args(args)\n                .observable(source.isObservable())\n                .observableExecutionMode(source.getObservableExecutionMode())\n                .defaultCollapserKey(source.getDefaultCollapserKey())\n                .defaultCommandKey(source.getDefaultCommandKey())\n                .defaultGroupKey(source.getDefaultGroupKey())\n                .defaultThreadPoolKey(source.getDefaultThreadPoolKey())\n                .defaultProperties(source.getDefaultProperties().orNull())\n                .hystrixCollapser(source.getHystrixCollapser())\n                .hystrixCommand(source.getHystrixCommand()).build();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/MetaHolder.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport com.google.common.base.Function;\nimport com.google.common.base.Optional;\nimport com.google.common.base.Predicate;\nimport com.google.common.base.Supplier;\nimport com.google.common.collect.ImmutableList;\nimport com.netflix.hystrix.contrib.javanica.annotation.*;\nimport com.netflix.hystrix.contrib.javanica.command.closure.Closure;\nimport org.apache.commons.lang3.StringUtils;\nimport org.aspectj.lang.JoinPoint;\n\nimport javax.annotation.Nullable;\nimport javax.annotation.concurrent.Immutable;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Simple immutable holder to keep all necessary information about current method to build Hystrix command.\n */\n// todo: replace fallback related flags with FallbackMethod class\n@Immutable\npublic final class MetaHolder {\n\n    private final HystrixCollapser hystrixCollapser;\n    private final HystrixCommand hystrixCommand;\n    private final DefaultProperties defaultProperties;\n\n    private final Method method;\n    private final Method cacheKeyMethod;\n    private final Method ajcMethod;\n    private final Method fallbackMethod;\n    private final Object obj;\n    private final Object proxyObj;\n    private final Object[] args;\n    private final Closure closure;\n    private final String defaultGroupKey;\n    private final String defaultCommandKey;\n    private final String defaultCollapserKey;\n    private final String defaultThreadPoolKey;\n    private final ExecutionType executionType;\n    private final boolean extendedFallback;\n    private final ExecutionType collapserExecutionType;\n    private final ExecutionType fallbackExecutionType;\n    private final boolean fallback;\n    private boolean extendedParentFallback;\n    private final boolean defaultFallback;\n    private final JoinPoint joinPoint;\n    private final boolean observable;\n    private final ObservableExecutionMode observableExecutionMode;\n\n    private static final Function identityFun = new Function<Object, Object>() {\n        @Nullable\n        @Override\n        public Object apply(@Nullable Object input) {\n            return input;\n        }\n    };\n\n    private MetaHolder(Builder builder) {\n        this.hystrixCommand = builder.hystrixCommand;\n        this.method = builder.method;\n        this.cacheKeyMethod = builder.cacheKeyMethod;\n        this.fallbackMethod = builder.fallbackMethod;\n        this.ajcMethod = builder.ajcMethod;\n        this.obj = builder.obj;\n        this.proxyObj = builder.proxyObj;\n        this.args = builder.args;\n        this.closure = builder.closure;\n        this.defaultGroupKey = builder.defaultGroupKey;\n        this.defaultCommandKey = builder.defaultCommandKey;\n        this.defaultThreadPoolKey = builder.defaultThreadPoolKey;\n        this.defaultCollapserKey = builder.defaultCollapserKey;\n        this.defaultProperties = builder.defaultProperties;\n        this.hystrixCollapser = builder.hystrixCollapser;\n        this.executionType = builder.executionType;\n        this.collapserExecutionType = builder.collapserExecutionType;\n        this.fallbackExecutionType = builder.fallbackExecutionType;\n        this.joinPoint = builder.joinPoint;\n        this.extendedFallback = builder.extendedFallback;\n        this.defaultFallback = builder.defaultFallback;\n        this.fallback = builder.fallback;\n        this.extendedParentFallback = builder.extendedParentFallback;\n        this.observable = builder.observable;\n        this.observableExecutionMode = builder.observableExecutionMode;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public HystrixCollapser getHystrixCollapser() {\n        return hystrixCollapser;\n    }\n\n    public HystrixCommand getHystrixCommand() {\n        return hystrixCommand;\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    public Method getCacheKeyMethod() {\n        return cacheKeyMethod;\n    }\n\n    public Method getAjcMethod() {\n        return ajcMethod;\n    }\n\n    public Object getObj() {\n        return obj;\n    }\n\n    public Object getProxyObj() {\n        return proxyObj;\n    }\n\n    public Closure getClosure() {\n        return closure;\n    }\n\n    public ExecutionType getExecutionType() {\n        return executionType;\n    }\n\n    public ExecutionType getCollapserExecutionType() {\n        return collapserExecutionType;\n    }\n\n    public Object[] getArgs() {\n        return args != null ? Arrays.copyOf(args, args.length) : new Object[]{};\n    }\n\n    public String getCommandGroupKey() {\n        return isCommandAnnotationPresent() ? get(hystrixCommand.groupKey(), defaultGroupKey) : \"\";\n    }\n\n    public String getDefaultGroupKey() {\n        return defaultGroupKey;\n    }\n\n    public String getDefaultThreadPoolKey() {\n        return defaultThreadPoolKey;\n    }\n\n    public String getCollapserKey() {\n        return isCollapserAnnotationPresent() ? get(hystrixCollapser.collapserKey(), defaultCollapserKey) : \"\";\n    }\n\n    public String getCommandKey() {\n        return isCommandAnnotationPresent() ? get(hystrixCommand.commandKey(), defaultCommandKey) : \"\";\n    }\n\n    public String getThreadPoolKey() {\n        return isCommandAnnotationPresent() ? get(hystrixCommand.threadPoolKey(), defaultThreadPoolKey) : \"\";\n    }\n\n    public String getDefaultCommandKey() {\n        return defaultCommandKey;\n    }\n\n    public String getDefaultCollapserKey() {\n        return defaultCollapserKey;\n    }\n\n    public boolean hasDefaultProperties() {\n        return defaultProperties != null;\n    }\n\n    public Optional<DefaultProperties> getDefaultProperties() {\n        return Optional.fromNullable(defaultProperties);\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return method.getParameterTypes();\n    }\n\n    public boolean isCollapserAnnotationPresent() {\n        return hystrixCollapser != null;\n    }\n\n    public boolean isCommandAnnotationPresent() {\n        return hystrixCommand != null;\n    }\n\n    public JoinPoint getJoinPoint() {\n        return joinPoint;\n    }\n\n    public Method getFallbackMethod() {\n        return fallbackMethod;\n    }\n\n    public boolean hasFallbackMethod() {\n        return fallbackMethod != null;\n    }\n\n    public boolean isExtendedParentFallback() {\n        return extendedParentFallback;\n    }\n\n    public boolean hasFallbackMethodCommand() {\n        return fallbackMethod != null && fallbackMethod.isAnnotationPresent(HystrixCommand.class);\n    }\n\n    public boolean isFallback() {\n        return fallback;\n    }\n\n    public boolean isExtendedFallback() {\n        return extendedFallback;\n    }\n\n    public boolean isDefaultFallback() {\n        return defaultFallback;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List<Class<? extends Throwable>> getCommandIgnoreExceptions() {\n        if (!isCommandAnnotationPresent()) return Collections.emptyList();\n        return getOrDefault(new Supplier<List<Class<? extends Throwable>>>() {\n            @Override\n            public List<Class<? extends Throwable>> get() {\n                return ImmutableList.<Class<? extends Throwable>>copyOf(hystrixCommand.ignoreExceptions());\n            }\n        }, new Supplier<List<Class<? extends Throwable>>>() {\n            @Override\n            public List<Class<? extends Throwable>> get() {\n                return hasDefaultProperties()\n                        ? ImmutableList.<Class<? extends Throwable>>copyOf(defaultProperties.ignoreExceptions())\n                        : Collections.<Class<? extends Throwable>>emptyList();\n            }\n        }, this.<Class<? extends Throwable>>nonEmptyList());\n    }\n\n    public ExecutionType getFallbackExecutionType() {\n        return fallbackExecutionType;\n    }\n\n    public List<HystrixProperty> getCommandProperties() {\n        if (!isCommandAnnotationPresent()) return Collections.emptyList();\n        return getOrDefault(new Supplier<List<HystrixProperty>>() {\n            @Override\n            public List<HystrixProperty> get() {\n                return ImmutableList.copyOf(hystrixCommand.commandProperties());\n            }\n        }, new Supplier<List<HystrixProperty>>() {\n            @Override\n            public List<HystrixProperty> get() {\n                return hasDefaultProperties()\n                        ? ImmutableList.copyOf(defaultProperties.commandProperties())\n                        : Collections.<HystrixProperty>emptyList();\n            }\n        }, this.<HystrixProperty>nonEmptyList());\n    }\n\n    public List<HystrixProperty> getCollapserProperties() {\n        return isCollapserAnnotationPresent() ? ImmutableList.copyOf(hystrixCollapser.collapserProperties()) : Collections.<HystrixProperty>emptyList();\n    }\n\n    public List<HystrixProperty> getThreadPoolProperties() {\n        if (!isCommandAnnotationPresent()) return Collections.emptyList();\n        return getOrDefault(new Supplier<List<HystrixProperty>>() {\n            @Override\n            public List<HystrixProperty> get() {\n                return ImmutableList.copyOf(hystrixCommand.threadPoolProperties());\n            }\n        }, new Supplier<List<HystrixProperty>>() {\n            @Override\n            public List<HystrixProperty> get() {\n                return hasDefaultProperties()\n                        ? ImmutableList.copyOf(defaultProperties.threadPoolProperties())\n                        : Collections.<HystrixProperty>emptyList();\n            }\n        }, this.<HystrixProperty>nonEmptyList());\n    }\n\n    public boolean isObservable() {\n        return observable;\n    }\n\n    public ObservableExecutionMode getObservableExecutionMode() {\n        return observableExecutionMode;\n    }\n\n    public boolean raiseHystrixExceptionsContains(HystrixException hystrixException) {\n        return getRaiseHystrixExceptions().contains(hystrixException);\n    }\n\n    public List<HystrixException> getRaiseHystrixExceptions() {\n        return getOrDefault(new Supplier<List<HystrixException>>() {\n            @Override\n            public List<HystrixException> get() {\n                return ImmutableList.copyOf(hystrixCommand.raiseHystrixExceptions());\n            }\n        }, new Supplier<List<HystrixException>>() {\n            @Override\n            public List<HystrixException> get() {\n                return hasDefaultProperties()\n                        ? ImmutableList.copyOf(defaultProperties.raiseHystrixExceptions())\n                        : Collections.<HystrixException>emptyList();\n\n            }\n        }, this.<HystrixException>nonEmptyList());\n    }\n\n    private String get(String key, String defaultKey) {\n        return StringUtils.isNotBlank(key) ? key : defaultKey;\n    }\n\n    private <T> Predicate<List<T>> nonEmptyList() {\n        return new Predicate<List<T>>() {\n            @Override\n            public boolean apply(@Nullable List<T> input) {\n                return input != null && !input.isEmpty();\n            }\n        };\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> T getOrDefault(Supplier<T> source, Supplier<T> defaultChoice, Predicate<T> isDefined) {\n        return getOrDefault(source, defaultChoice, isDefined, (Function<T, T>) identityFun);\n    }\n\n    private <T> T getOrDefault(Supplier<T> source, Supplier<T> defaultChoice, Predicate<T> isDefined, Function<T, T> map) {\n        T res = source.get();\n        if (!isDefined.apply(res)) {\n            res = defaultChoice.get();\n        }\n        return map.apply(res);\n    }\n\n    public static final class Builder {\n\n        private static final Class<?>[] EMPTY_ARRAY_OF_TYPES= new Class[0];\n\n        private HystrixCollapser hystrixCollapser;\n        private HystrixCommand hystrixCommand;\n        private DefaultProperties defaultProperties;\n        private Method method;\n        private Method cacheKeyMethod;\n        private Method fallbackMethod;\n        private Method ajcMethod;\n        private Object obj;\n        private Object proxyObj;\n        private Closure closure;\n        private Object[] args;\n        private String defaultGroupKey;\n        private String defaultCommandKey;\n        private String defaultCollapserKey;\n        private String defaultThreadPoolKey;\n        private ExecutionType executionType;\n        private ExecutionType collapserExecutionType;\n        private ExecutionType fallbackExecutionType;\n        private boolean extendedFallback;\n        private boolean fallback;\n        private boolean extendedParentFallback;\n        private boolean defaultFallback;\n        private boolean observable;\n        private JoinPoint joinPoint;\n        private ObservableExecutionMode observableExecutionMode;\n\n        public Builder hystrixCollapser(HystrixCollapser hystrixCollapser) {\n            this.hystrixCollapser = hystrixCollapser;\n            return this;\n        }\n\n        public Builder hystrixCommand(HystrixCommand hystrixCommand) {\n            this.hystrixCommand = hystrixCommand;\n            return this;\n        }\n\n        public Builder method(Method method) {\n            this.method = method;\n            return this;\n        }\n\n        public Builder cacheKeyMethod(Method cacheKeyMethod) {\n            this.cacheKeyMethod = cacheKeyMethod;\n            return this;\n        }\n\n        public Builder fallbackMethod(Method fallbackMethod) {\n            this.fallbackMethod = fallbackMethod;\n            return this;\n        }\n\n        public Builder fallbackExecutionType(ExecutionType fallbackExecutionType) {\n            this.fallbackExecutionType = fallbackExecutionType;\n            return this;\n        }\n\n        public Builder fallback(boolean fallback) {\n            this.fallback = fallback;\n            return this;\n        }\n\n        public Builder extendedParentFallback(boolean extendedParentFallback) {\n            this.extendedParentFallback = extendedParentFallback;\n            return this;\n        }\n\n        public Builder defaultFallback(boolean defaultFallback) {\n            this.defaultFallback = defaultFallback;\n            return this;\n        }\n\n        public Builder ajcMethod(Method ajcMethod) {\n            this.ajcMethod = ajcMethod;\n            return this;\n        }\n\n        public Builder obj(Object obj) {\n            this.obj = obj;\n            return this;\n        }\n\n        public Builder proxyObj(Object proxy) {\n            this.proxyObj = proxy;\n            return this;\n        }\n\n        public Builder args(Object[] args) {\n            this.args = args;\n            return this;\n        }\n\n        public Builder closure(Closure closure) {\n            this.closure = closure;\n            return this;\n        }\n\n        public Builder executionType(ExecutionType executionType) {\n            this.executionType = executionType;\n            return this;\n        }\n\n        public Builder collapserExecutionType(ExecutionType collapserExecutionType) {\n            this.collapserExecutionType = collapserExecutionType;\n            return this;\n        }\n\n        public Builder defaultGroupKey(String defGroupKey) {\n            this.defaultGroupKey = defGroupKey;\n            return this;\n        }\n\n        public Builder defaultCommandKey(String defCommandKey) {\n            this.defaultCommandKey = defCommandKey;\n            return this;\n        }\n\n        public Builder defaultThreadPoolKey(String defaultThreadPoolKey) {\n            this.defaultThreadPoolKey = defaultThreadPoolKey;\n            return this;\n        }\n\n        public Builder defaultCollapserKey(String defCollapserKey) {\n            this.defaultCollapserKey = defCollapserKey;\n            return this;\n        }\n\n        public Builder defaultProperties(@Nullable DefaultProperties defaultProperties) {\n            this.defaultProperties = defaultProperties;\n            return this;\n        }\n\n        public Builder joinPoint(JoinPoint joinPoint) {\n            this.joinPoint = joinPoint;\n            return this;\n        }\n\n        public Builder extendedFallback(boolean extendedFallback) {\n            this.extendedFallback = extendedFallback;\n            return this;\n        }\n\n        public Builder observable(boolean observable) {\n            this.observable = observable;\n            return this;\n        }\n\n        public Builder observableExecutionMode(ObservableExecutionMode observableExecutionMode) {\n            this.observableExecutionMode = observableExecutionMode;\n            return this;\n        }\n\n        public MetaHolder build() {\n            return new MetaHolder(this);\n        }\n\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/MethodExecutionAction.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\n\nimport com.netflix.hystrix.contrib.javanica.command.closure.AsyncClosureFactory;\nimport com.netflix.hystrix.contrib.javanica.command.closure.Closure;\nimport com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;\nimport com.netflix.hystrix.contrib.javanica.exception.ExceptionUtils;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;\nimport static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.invokeAjcMethod;\n\n/**\n * This implementation invokes methods using java reflection.\n * If {@link Method#invoke(Object, Object...)} throws exception then this exception is wrapped to {@link CommandActionExecutionException}\n * for further unwrapping and processing.\n */\npublic class MethodExecutionAction implements CommandAction {\n\n    private static final Object[] EMPTY_ARGS = new Object[]{};\n\n    private final Object object;\n    private final Method method;\n    private final Object[] _args;\n    private final MetaHolder metaHolder;\n\n\n    public MethodExecutionAction(Object object, Method method, MetaHolder metaHolder) {\n        this.object = object;\n        this.method = method;\n        this._args = EMPTY_ARGS;\n        this.metaHolder = metaHolder;\n    }\n\n    public MethodExecutionAction(Object object, Method method, Object[] args, MetaHolder metaHolder){\n        this.object = object;\n        this.method = method;\n        this._args = args;\n        this.metaHolder = metaHolder;\n    }\n\n    public Object getObject() {\n        return object;\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    public Object[] getArgs() {\n        return _args;\n    }\n\n    @Override\n    public MetaHolder getMetaHolder() {\n        return metaHolder;\n    }\n\n    @Override\n    public Object execute(ExecutionType executionType) throws CommandActionExecutionException {\n        return executeWithArgs(executionType, _args);\n    }\n\n    /**\n     * Invokes the method. Also private method also can be invoked.\n     *\n     * @return result of execution\n     */\n    @Override\n    public Object executeWithArgs(ExecutionType executionType, Object[] args) throws CommandActionExecutionException {\n        if(ExecutionType.ASYNCHRONOUS == executionType){\n            Closure closure = AsyncClosureFactory.getInstance().createClosure(metaHolder, method, object, args);\n            return executeClj(closure.getClosureObj(), closure.getClosureMethod());\n        }\n\n        return execute(object, method, args);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String getActionName() {\n        return method.getName();\n    }\n\n    /**\n     * Invokes the method.\n     *\n     * @return result of execution\n     */\n    private Object execute(Object o, Method m, Object... args) throws CommandActionExecutionException {\n        Object result = null;\n        try {\n            m.setAccessible(true); // suppress Java language access\n            if (isCompileWeaving() && metaHolder.getAjcMethod() != null) {\n                result = invokeAjcMethod(metaHolder.getAjcMethod(), o, metaHolder, args);\n            } else {\n                result = m.invoke(o, args);\n            }\n        } catch (IllegalAccessException e) {\n            propagateCause(e);\n        } catch (InvocationTargetException e) {\n            propagateCause(e);\n        }\n        return result;\n    }\n\n    private Object executeClj(Object o, Method m, Object... args){\n        Object result = null;\n        try {\n            m.setAccessible(true); // suppress Java language access\n            result = m.invoke(o, args);\n        } catch (IllegalAccessException e) {\n            propagateCause(e);\n        } catch (InvocationTargetException e) {\n            propagateCause(e);\n        }\n        return result;\n    }\n\n    /**\n     * Retrieves cause exception and wraps to {@link CommandActionExecutionException}.\n     *\n     * @param throwable the throwable\n     */\n    private void propagateCause(Throwable throwable) throws CommandActionExecutionException {\n        ExceptionUtils.propagateCause(throwable);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/closure/AbstractClosureFactory.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command.closure;\n\nimport com.google.common.base.Throwables;\nimport com.netflix.hystrix.contrib.javanica.command.ClosureCommand;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving;\nimport static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.invokeAjcMethod;\nimport static org.slf4j.helpers.MessageFormatter.format;\n\n/**\n * Abstract implementation of {@link ClosureFactory}.\n */\npublic abstract class AbstractClosureFactory implements ClosureFactory {\n\n    static final String ERROR_TYPE_MESSAGE = \"return type of '{}' method should be {}.\";\n    static final String INVOKE_METHOD = \"invoke\";\n\n    @Override\n    public Closure createClosure(MetaHolder metaHolder, Method method, Object o, Object... args) {\n        try {\n            Object closureObj;\n            method.setAccessible(true);\n            if (isCompileWeaving()) {\n                closureObj = invokeAjcMethod(metaHolder.getAjcMethod(), o, metaHolder, args);\n            } else {\n                closureObj = method.invoke(o, args); // creates instance of an anonymous class\n            }\n            return createClosure(method.getName(), closureObj);\n        } catch (InvocationTargetException e) {\n            throw Throwables.propagate(e.getCause());\n        } catch (Exception e) {\n            throw Throwables.propagate(e);\n        }\n    }\n\n    /**\n     * Creates closure.\n     *\n     * @param rootMethodName the name of external method within which closure is created.\n     * @param closureObj     the instance of specific anonymous class\n     * @return new {@link Closure} instance\n     * @throws Exception\n     */\n    Closure createClosure(String rootMethodName, final Object closureObj) throws Exception {\n        if (!isClosureCommand(closureObj)) {\n            throw new RuntimeException(format(ERROR_TYPE_MESSAGE, rootMethodName,\n                    getClosureCommandType().getName()).getMessage());\n        }\n        Method closureMethod = closureObj.getClass().getMethod(INVOKE_METHOD);\n        return new Closure(closureMethod, closureObj);\n    }\n\n    /**\n     * Checks that closureObj is instance of necessary class.\n     *\n     * @param closureObj the instance of an anonymous class\n     * @return true of closureObj has expected type, otherwise - false\n     */\n    abstract boolean isClosureCommand(final Object closureObj);\n\n    /**\n     * Gets type of expected closure type.\n     *\n     * @return closure (anonymous class) type\n     */\n    abstract Class<? extends ClosureCommand> getClosureCommandType();\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/closure/AsyncClosureFactory.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command.closure;\n\nimport com.netflix.hystrix.contrib.javanica.command.AsyncResult;\nimport com.netflix.hystrix.contrib.javanica.command.ClosureCommand;\n\n/**\n * Specific implementation of {@link ClosureFactory}.\n */\npublic class AsyncClosureFactory extends AbstractClosureFactory {\n\n    private static final AsyncClosureFactory INSTANCE = new AsyncClosureFactory();\n\n    private AsyncClosureFactory() {\n    }\n\n    public static AsyncClosureFactory getInstance() {\n        return INSTANCE;\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    boolean isClosureCommand(Object closureObj) {\n        return closureObj instanceof AsyncResult;\n    }\n\n    /**\n     * {@inheritDoc}.\n     */\n    @Override\n    Class<? extends ClosureCommand> getClosureCommandType() {\n        return AsyncResult.class;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/closure/Closure.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command.closure;\n\nimport java.lang.reflect.Method;\n\n/**\n * Contains method and instance of anonymous class which implements\n * {@link com.netflix.hystrix.contrib.javanica.command.ClosureCommand} interface.\n */\npublic class Closure {\n\n    private final Method closureMethod;\n    private final Object closureObj;\n\n    public Closure() {\n        closureMethod = null;\n        closureObj = null;\n    }\n\n    public Closure(Method closureMethod, Object closureObj) {\n        this.closureMethod = closureMethod;\n        this.closureObj = closureObj;\n    }\n\n    public Method getClosureMethod() {\n        return closureMethod;\n    }\n\n    public Object getClosureObj() {\n        return closureObj;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/closure/ClosureFactory.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command.closure;\n\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\n\nimport java.lang.reflect.Method;\n\n/**\n * Factory to create instances of {@link Closure} class.\n */\npublic interface ClosureFactory {\n\n    /**\n     * Creates closure in accordance with method return type.\n     *\n     * @param metaHolder the meta holder\n     * @param method the external method within which closure is created\n     * @param o      the object the underlying method is invoked from\n     * @param args   the arguments used for the method call\n     * @return new {@link Closure} instance\n     */\n    Closure createClosure(final MetaHolder metaHolder, final Method method, final Object o, final Object... args);\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/conf/HystrixPropertiesManager.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.conf;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport org.apache.commons.lang3.Validate;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * This class provides methods to set hystrix properties.\n */\npublic final class HystrixPropertiesManager {\n\n    private HystrixPropertiesManager() {\n    }\n\n    /**\n     * Command execution properties.\n     */\n    public static final String EXECUTION_ISOLATION_STRATEGY = \"execution.isolation.strategy\";\n    public static final String EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS = \"execution.isolation.thread.timeoutInMilliseconds\";\n    public static final String EXECUTION_TIMEOUT_ENABLED = \"execution.timeout.enabled\";\n    public static final String EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT = \"execution.isolation.thread.interruptOnTimeout\";\n    public static final String EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS = \"execution.isolation.semaphore.maxConcurrentRequests\";\n\n    /**\n     * Command fallback properties.\n     */\n    public static final String FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS = \"fallback.isolation.semaphore.maxConcurrentRequests\";\n    public static final String FALLBACK_ENABLED = \"fallback.enabled\";\n\n    /**\n     * Command circuit breaker properties.\n     */\n    public static final String CIRCUIT_BREAKER_ENABLED = \"circuitBreaker.enabled\";\n    public static final String CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD = \"circuitBreaker.requestVolumeThreshold\";\n    public static final String CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS = \"circuitBreaker.sleepWindowInMilliseconds\";\n    public static final String CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE = \"circuitBreaker.errorThresholdPercentage\";\n    public static final String CIRCUIT_BREAKER_FORCE_OPEN = \"circuitBreaker.forceOpen\";\n    public static final String CIRCUIT_BREAKER_FORCE_CLOSED = \"circuitBreaker.forceClosed\";\n\n    /**\n     * Command metrics properties.\n     */\n    public static final String METRICS_ROLLING_PERCENTILE_ENABLED = \"metrics.rollingPercentile.enabled\";\n    public static final String METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS = \"metrics.rollingPercentile.timeInMilliseconds\";\n    public static final String METRICS_ROLLING_PERCENTILE_NUM_BUCKETS = \"metrics.rollingPercentile.numBuckets\";\n    public static final String METRICS_ROLLING_PERCENTILE_BUCKET_SIZE = \"metrics.rollingPercentile.bucketSize\";\n    public static final String METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS = \"metrics.healthSnapshot.intervalInMilliseconds\";\n\n    /**\n     * Command CommandRequest Context properties.\n     */\n    public static final String REQUEST_CACHE_ENABLED = \"requestCache.enabled\";\n    public static final String REQUEST_LOG_ENABLED = \"requestLog.enabled\";\n\n    /**\n     * Thread pool properties.\n     */\n    public static final String MAX_QUEUE_SIZE = \"maxQueueSize\";\n    public static final String CORE_SIZE = \"coreSize\";\n    public static final String MAXIMUM_SIZE = \"maximumSize\";\n    public static final String ALLOW_MAXIMUM_SIZE_TO_DIVERGE_FROM_CORE_SIZE = \"allowMaximumSizeToDivergeFromCoreSize\";\n    public static final String KEEP_ALIVE_TIME_MINUTES = \"keepAliveTimeMinutes\";\n    public static final String QUEUE_SIZE_REJECTION_THRESHOLD = \"queueSizeRejectionThreshold\";\n    public static final String METRICS_ROLLING_STATS_NUM_BUCKETS = \"metrics.rollingStats.numBuckets\";\n    public static final String METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS = \"metrics.rollingStats.timeInMilliseconds\";\n\n    /**\n     * Collapser properties.\n     */\n    public static final String MAX_REQUESTS_IN_BATCH = \"maxRequestsInBatch\";\n    public static final String TIMER_DELAY_IN_MILLISECONDS = \"timerDelayInMilliseconds\";\n\n    /**\n     * Creates and sets Hystrix command properties.\n     *\n     * @param properties the collapser properties\n     */\n    public static HystrixCommandProperties.Setter initializeCommandProperties(List<HystrixProperty> properties) throws IllegalArgumentException {\n        return initializeProperties(HystrixCommandProperties.Setter(), properties, CMD_PROP_MAP, \"command\");\n    }\n\n    /**\n     * Creates and sets Hystrix thread pool properties.\n     *\n     * @param properties the collapser properties\n     */\n    public static HystrixThreadPoolProperties.Setter initializeThreadPoolProperties(List<HystrixProperty> properties) throws IllegalArgumentException {\n        return initializeProperties(HystrixThreadPoolProperties.Setter(), properties, TP_PROP_MAP, \"thread pool\");\n    }\n\n    /**\n     * Creates and sets Hystrix collapser properties.\n     *\n     * @param properties the collapser properties\n     */\n    public static HystrixCollapserProperties.Setter initializeCollapserProperties(List<HystrixProperty> properties) {\n        return initializeProperties(HystrixCollapserProperties.Setter(), properties, COLLAPSER_PROP_MAP, \"collapser\");\n    }\n\n    private static <S> S initializeProperties(S setter, List<HystrixProperty> properties, Map<String, PropSetter<S, String>> propMap, String type) {\n        if (properties != null && properties.size() > 0) {\n            for (HystrixProperty property : properties) {\n                validate(property);\n                if (!propMap.containsKey(property.name())) {\n                    throw new IllegalArgumentException(\"unknown \" + type + \" property: \" + property.name());\n                }\n\n                propMap.get(property.name()).set(setter, property.value());\n            }\n        }\n        return setter;\n    }\n\n    private static void validate(HystrixProperty hystrixProperty) throws IllegalArgumentException {\n        Validate.notBlank(hystrixProperty.name(), \"hystrix property name cannot be null or blank\");\n    }\n\n    private static final Map<String, PropSetter<HystrixCommandProperties.Setter, String>> CMD_PROP_MAP =\n            ImmutableMap.<String, PropSetter<HystrixCommandProperties.Setter, String>>builder()\n                    .put(EXECUTION_ISOLATION_STRATEGY, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withExecutionIsolationStrategy(toEnum(EXECUTION_ISOLATION_STRATEGY, value, HystrixCommandProperties.ExecutionIsolationStrategy.class,\n                                    HystrixCommandProperties.ExecutionIsolationStrategy.values()));\n                        }\n                    })\n                    .put(EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withExecutionTimeoutInMilliseconds(toInt(EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(EXECUTION_TIMEOUT_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withExecutionTimeoutEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withExecutionIsolationThreadInterruptOnTimeout(toBoolean(value));\n                        }\n                    })\n                    .put(EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(toInt(EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value));\n                        }\n                    })\n                    .put(FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withFallbackIsolationSemaphoreMaxConcurrentRequests(toInt(FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value));\n                        }\n                    })\n                    .put(FALLBACK_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withFallbackEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerRequestVolumeThreshold(toInt(CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerSleepWindowInMilliseconds(toInt(CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerErrorThresholdPercentage(toInt(CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_FORCE_OPEN, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerForceOpen(toBoolean(value));\n                        }\n                    })\n                    .put(CIRCUIT_BREAKER_FORCE_CLOSED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withCircuitBreakerForceClosed(toBoolean(value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingStatisticalWindowInMilliseconds(toInt(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_STATS_NUM_BUCKETS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingStatisticalWindowBuckets(toInt(METRICS_ROLLING_STATS_NUM_BUCKETS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileWindowInMilliseconds(toInt(METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileWindowBuckets(toInt(METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileBucketSize(toInt(METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, value));\n                        }\n                    })\n                    .put(METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsHealthSnapshotIntervalInMilliseconds(toInt(METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(REQUEST_CACHE_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withRequestCacheEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(REQUEST_LOG_ENABLED, new PropSetter<HystrixCommandProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCommandProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withRequestLogEnabled(toBoolean(value));\n                        }\n                    })\n                    .build();\n\n\n    private static final Map<String, PropSetter<HystrixThreadPoolProperties.Setter, String>> TP_PROP_MAP =\n            ImmutableMap.<String, PropSetter<HystrixThreadPoolProperties.Setter, String>>builder()\n                    .put(MAX_QUEUE_SIZE, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                            setter.withMaxQueueSize(toInt(MAX_QUEUE_SIZE, value));\n                        }\n                    })\n                    .put(CORE_SIZE, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withCoreSize(toInt(CORE_SIZE, value));\n                                }\n                            }\n                    )\n                    .put(MAXIMUM_SIZE, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withMaximumSize(toInt(MAXIMUM_SIZE, value));\n                                }\n                            }\n                    )\n                    .put(ALLOW_MAXIMUM_SIZE_TO_DIVERGE_FROM_CORE_SIZE, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixThreadPoolProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withAllowMaximumSizeToDivergeFromCoreSize(toBoolean(value));\n                        }\n                    })\n                    .put(KEEP_ALIVE_TIME_MINUTES, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withKeepAliveTimeMinutes(toInt(KEEP_ALIVE_TIME_MINUTES, value));\n                                }\n                            }\n                    )\n                    .put(QUEUE_SIZE_REJECTION_THRESHOLD, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withQueueSizeRejectionThreshold(toInt(QUEUE_SIZE_REJECTION_THRESHOLD, value));\n                                }\n                            }\n                    )\n                    .put(METRICS_ROLLING_STATS_NUM_BUCKETS, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withMetricsRollingStatisticalWindowBuckets(toInt(METRICS_ROLLING_STATS_NUM_BUCKETS, value));\n                                }\n                            }\n                    )\n                    .put(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, new PropSetter<HystrixThreadPoolProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixThreadPoolProperties.Setter setter, String value) {\n                                    setter.withMetricsRollingStatisticalWindowInMilliseconds(toInt(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value));\n                                }\n                            }\n                    )\n                    .build();\n\n\n    private static final Map<String, PropSetter<HystrixCollapserProperties.Setter, String>> COLLAPSER_PROP_MAP =\n            ImmutableMap.<String, PropSetter<HystrixCollapserProperties.Setter, String>>builder()\n                    .put(TIMER_DELAY_IN_MILLISECONDS, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) {\n                            setter.withTimerDelayInMilliseconds(toInt(TIMER_DELAY_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(MAX_REQUESTS_IN_BATCH, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                                @Override\n                                public void set(HystrixCollapserProperties.Setter setter, String value) {\n                                    setter.withMaxRequestsInBatch(toInt(MAX_REQUESTS_IN_BATCH, value));\n                                }\n                            }\n                    )\n                    .put(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingStatisticalWindowInMilliseconds(toInt(METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_STATS_NUM_BUCKETS, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingStatisticalWindowBuckets(toInt(METRICS_ROLLING_STATS_NUM_BUCKETS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_ENABLED, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileEnabled(toBoolean(value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileWindowInMilliseconds(toInt(METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileWindowBuckets(toInt(METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, value));\n                        }\n                    })\n                    .put(METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withMetricsRollingPercentileBucketSize(toInt(METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, value));\n                        }\n                    })\n                    .put(REQUEST_CACHE_ENABLED, new PropSetter<HystrixCollapserProperties.Setter, String>() {\n                        @Override\n                        public void set(HystrixCollapserProperties.Setter setter, String value) throws IllegalArgumentException {\n                            setter.withRequestCacheEnabled(toBoolean(value));\n                        }\n                    })\n                    .build();\n\n\n    private interface PropSetter<S, V> {\n        void set(S setter, V value) throws IllegalArgumentException;\n    }\n\n    private static <E extends Enum<E>> E toEnum(String propName, String propValue, Class<E> enumType, E... values) throws IllegalArgumentException {\n        try {\n            return Enum.valueOf(enumType, propValue);\n        } catch (NullPointerException npe) {\n            throw createBadEnumError(propName, propValue, values);\n        } catch (IllegalArgumentException e) {\n            throw createBadEnumError(propName, propValue, values);\n        }\n    }\n\n    private static int toInt(String propName, String propValue) throws IllegalArgumentException {\n        try {\n            return Integer.parseInt(propValue);\n        } catch (NumberFormatException e) {\n            throw new IllegalArgumentException(\"bad property value. property name '\" + propName + \"'. Expected int value, actual = \" + propValue);\n        }\n    }\n\n    private static boolean toBoolean(String propValue) {\n        return Boolean.valueOf(propValue);\n    }\n\n    private static IllegalArgumentException createBadEnumError(String propName, String propValue, Enum... values) {\n        throw new IllegalArgumentException(\"bad property value. property name '\" + propName + \"'. Expected correct enum value, one of the [\" + Arrays.toString(values) + \"] , actual = \" + propValue);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/CommandActionExecutionException.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n/**\n * This exception is used to wrap original exceptions to push through javanica infrastructure.\n */\npublic class CommandActionExecutionException extends RuntimeException {\n\n    /**\n     * Creates exceptions instance with cause is original exception.\n     *\n     * @param cause the original exception\n     */\n    public CommandActionExecutionException(Throwable cause) {\n        super(cause);\n    }\n\n    /**\n     * Default constructor.\n     */\n    public CommandActionExecutionException() {\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/ExceptionUtils.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\n\n/**\n * Util class to work with exceptions.\n */\npublic class ExceptionUtils {\n\n    /**\n     * Retrieves cause exception and wraps to {@link CommandActionExecutionException}.\n     *\n     * @param throwable the throwable\n     */\n    public static void propagateCause(Throwable throwable) throws CommandActionExecutionException {\n        throw new CommandActionExecutionException(throwable.getCause());\n    }\n\n    /**\n     * Wraps cause exception to {@link CommandActionExecutionException}.\n     *\n     * @param throwable the throwable\n     */\n    public static CommandActionExecutionException wrapCause(Throwable throwable) {\n        return new CommandActionExecutionException(throwable.getCause());\n    }\n\n    /**\n     * Gets actual exception if it's wrapped in {@link CommandActionExecutionException} or {@link HystrixBadRequestException}.\n     *\n     * @param e the exception\n     * @return unwrapped\n     */\n    public static Throwable unwrapCause(Throwable e) {\n        if (e instanceof CommandActionExecutionException) {\n            return e.getCause();\n        }\n        if (e instanceof HystrixBadRequestException) {\n            return e.getCause();\n        }\n        return e;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/FallbackDefinitionException.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n\npublic class FallbackDefinitionException extends RuntimeException {\n\n    public FallbackDefinitionException() {\n    }\n\n    public FallbackDefinitionException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public FallbackDefinitionException(Throwable cause) {\n        super(cause);\n    }\n\n    public FallbackDefinitionException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/FallbackInvocationException.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n/**\n * Exception specifies error occurred in fallback method.\n */\npublic class FallbackInvocationException extends RuntimeException {\n\n    public FallbackInvocationException() {\n    }\n\n    public FallbackInvocationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public FallbackInvocationException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/HystrixCacheKeyGenerationException.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n/**\n * Indicates that something is going wrong with cache key generation logic.\n *\n * @author dmgcodevil\n */\npublic class HystrixCacheKeyGenerationException extends RuntimeException {\n\n    public HystrixCacheKeyGenerationException() {\n    }\n\n    public HystrixCacheKeyGenerationException(String message) {\n        super(message);\n    }\n\n    public HystrixCacheKeyGenerationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public HystrixCacheKeyGenerationException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/HystrixCachingException.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n/**\n * Indicates that something is going wrong with caching logic.\n *\n * @author dmgcodevil\n */\npublic class HystrixCachingException extends RuntimeException {\n\n    public HystrixCachingException() {\n    }\n\n    public HystrixCachingException(String message) {\n        super(message);\n    }\n\n    public HystrixCachingException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public HystrixCachingException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/exception/HystrixPropertyException.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.exception;\n\n/**\n * Created by dmgcodevil.\n */\npublic class HystrixPropertyException extends RuntimeException {\n\n    public HystrixPropertyException() {\n    }\n\n    public HystrixPropertyException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public HystrixPropertyException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/AopUtils.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport com.google.common.base.Optional;\nimport com.google.common.base.Throwables;\nimport org.apache.commons.lang3.Validate;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.reflect.MethodSignature;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.Type;\n\n/**\n * Provides common methods to retrieve information from JoinPoint and not only.\n */\npublic final class AopUtils {\n\n    private AopUtils() {\n        throw new UnsupportedOperationException(\"It's prohibited to create instances of the class.\");\n    }\n\n    /**\n     * Gets a {@link Method} object from target object (not proxy class).\n     *\n     * @param joinPoint the {@link JoinPoint}\n     * @return a {@link Method} object or null if method doesn't exist or if the signature at a join point\n     *         isn't sub-type of {@link MethodSignature}\n     */\n    public static Method getMethodFromTarget(JoinPoint joinPoint) {\n        Method method = null;\n        if (joinPoint.getSignature() instanceof MethodSignature) {\n            MethodSignature signature = (MethodSignature) joinPoint.getSignature();\n            method = getDeclaredMethod(joinPoint.getTarget().getClass(), signature.getName(),\n                    getParameterTypes(joinPoint));\n        }\n        return method;\n    }\n\n    /**\n     * Gets a {@link Method} object from target object by specified method name.\n     *\n     * @param joinPoint  the {@link JoinPoint}\n     * @param methodName the method name\n     * @return a {@link Method} object or null if method with specified <code>methodName</code> doesn't exist\n     */\n    public static Method getMethodFromTarget(JoinPoint joinPoint, String methodName) {\n        return getDeclaredMethod(joinPoint.getTarget().getClass(), methodName,\n                getParameterTypes(joinPoint));\n    }\n\n    /**\n     * Gets parameter types of the join point.\n     *\n     * @param joinPoint the join point\n     * @return the parameter types for the method this object\n     *         represents\n     */\n    public static Class[] getParameterTypes(JoinPoint joinPoint) {\n        MethodSignature signature = (MethodSignature) joinPoint.getSignature();\n        Method method = signature.getMethod();\n        return method.getParameterTypes();\n    }\n\n    /**\n     * Gets declared method from specified type by mame and parameters types.\n     *\n     * @param type           the type\n     * @param methodName     the name of the method\n     * @param parameterTypes the parameter array\n     * @return a {@link Method} object or null if method doesn't exist\n     */\n    public static Method getDeclaredMethod(Class<?> type, String methodName, Class<?>... parameterTypes) {\n        Method method = null;\n        try {\n            method = type.getDeclaredMethod(methodName, parameterTypes);\n            if(method.isBridge()){\n                method = MethodProvider.getInstance().unbride(method, type);\n            }\n        } catch (NoSuchMethodException e) {\n            Class<?> superclass = type.getSuperclass();\n            if (superclass != null) {\n                method = getDeclaredMethod(superclass, methodName, parameterTypes);\n            }\n        } catch (ClassNotFoundException e) {\n            Throwables.propagate(e);\n        } catch (IOException e) {\n            Throwables.propagate(e);\n        }\n        return method;\n    }\n\n    public static <T extends Annotation> Optional<T> getAnnotation(JoinPoint joinPoint, Class<T> annotation) {\n        return getAnnotation(joinPoint.getTarget().getClass(), annotation);\n    }\n\n    public static <T extends Annotation> Optional<T> getAnnotation(Class<?> type, Class<T> annotation) {\n        Validate.notNull(annotation, \"annotation cannot be null\");\n        Validate.notNull(type, \"type cannot be null\");\n        for (Annotation ann : type.getDeclaredAnnotations()) {\n            if (ann.annotationType().equals(annotation)) return Optional.of((T) ann);\n        }\n\n        Class<?> superType = type.getSuperclass();\n        if (superType != null && !superType.equals(Object.class)) {\n            return getAnnotation(superType, annotation);\n        }\n\n        return Optional.absent();\n    }\n\n    public static String getMethodInfo(Method m) {\n        StringBuilder info = new StringBuilder();\n        info.append(\"Method signature:\").append(\"\\n\");\n        info.append(m.toGenericString()).append(\"\\n\");\n\n        info.append(\"Declaring class:\\n\");\n        info.append(m.getDeclaringClass().getCanonicalName()).append(\"\\n\");\n\n        info.append(\"\\nFlags:\").append(\"\\n\");\n        info.append(\"Bridge=\").append(m.isBridge()).append(\"\\n\");\n        info.append(\"Synthetic=\").append(m.isSynthetic()).append(\"\\n\");\n        info.append(\"Final=\").append(Modifier.isFinal(m.getModifiers())).append(\"\\n\");\n        info.append(\"Native=\").append(Modifier.isNative(m.getModifiers())).append(\"\\n\");\n        info.append(\"Synchronized=\").append(Modifier.isSynchronized(m.getModifiers())).append(\"\\n\");\n        info.append(\"Abstract=\").append(Modifier.isAbstract(m.getModifiers())).append(\"\\n\");\n        info.append(\"AccessLevel=\").append(getAccessLevel(m.getModifiers())).append(\"\\n\");\n\n        info.append(\"\\nReturn Type: \\n\");\n        info.append(\"ReturnType=\").append(m.getReturnType()).append(\"\\n\");\n        info.append(\"GenericReturnType=\").append(m.getGenericReturnType()).append(\"\\n\");\n\n        info.append(\"\\nParameters:\");\n        Class<?>[] pType = m.getParameterTypes();\n        Type[] gpType = m.getGenericParameterTypes();\n        if (pType.length != 0) {\n            info.append(\"\\n\");\n        } else {\n            info.append(\"empty\\n\");\n        }\n        for (int i = 0; i < pType.length; i++) {\n            info.append(\"parameter [\").append(i).append(\"]:\\n\");\n            info.append(\"ParameterType=\").append(pType[i]).append(\"\\n\");\n            info.append(\"GenericParameterType=\").append(gpType[i]).append(\"\\n\");\n        }\n\n        info.append(\"\\nExceptions:\");\n        Class<?>[] xType = m.getExceptionTypes();\n        Type[] gxType = m.getGenericExceptionTypes();\n        if (xType.length != 0) {\n            info.append(\"\\n\");\n        } else {\n            info.append(\"empty\\n\");\n        }\n        for (int i = 0; i < xType.length; i++) {\n            info.append(\"exception [\").append(i).append(\"]:\\n\");\n            info.append(\"ExceptionType=\").append(xType[i]).append(\"\\n\");\n            info.append(\"GenericExceptionType=\").append(gxType[i]).append(\"\\n\");\n        }\n\n        info.append(\"\\nAnnotations:\");\n        if (m.getAnnotations().length != 0) {\n            info.append(\"\\n\");\n        } else {\n            info.append(\"empty\\n\");\n        }\n\n        for (int i = 0; i < m.getAnnotations().length; i++) {\n            info.append(\"annotation[\").append(i).append(\"]=\").append(m.getAnnotations()[i]).append(\"\\n\");\n        }\n\n        return info.toString();\n    }\n\n    private static String getAccessLevel(int modifiers) {\n        if (Modifier.isPublic(modifiers)) {\n            return \"public\";\n        } else if (Modifier.isProtected(modifiers)) {\n            return \"protected\";\n        } else if (Modifier.isPrivate(modifiers)) {\n            return \"private\";\n        } else {\n            return \"default\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/CommonUtils.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport org.apache.commons.lang3.ArrayUtils;\n\nimport java.util.Arrays;\n\n/**\n * Created by dmgcodevil.\n */\npublic final class CommonUtils {\n\n    private CommonUtils(){\n\n    }\n\n    public static Object[] createArgsForFallback(MetaHolder metaHolder, Throwable exception) {\n        return createArgsForFallback(metaHolder.getArgs(), metaHolder, exception);\n    }\n\n    public static Object[] createArgsForFallback(Object[] args, MetaHolder metaHolder, Throwable exception) {\n        if (metaHolder.isExtendedFallback()) {\n            if (metaHolder.isExtendedParentFallback()) {\n                args[args.length - 1] = exception;\n            } else {\n                args = Arrays.copyOf(args, args.length + 1);\n                args[args.length - 1] = exception;\n            }\n        } else {\n            if (metaHolder.isExtendedParentFallback()) {\n                args = ArrayUtils.remove(args, args.length - 1);\n            }\n        }\n        return args;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/EnvUtils.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport com.netflix.hystrix.contrib.javanica.aop.aspectj.WeavingMode;\n\nimport java.util.Arrays;\n\n/**\n * Created by dmgcodevil\n */\npublic final class EnvUtils {\n\t\n\tprivate static final String WEAVING_MODE;\n\t\n\tstatic {\n\t\tWEAVING_MODE = System.getProperty(\"weavingMode\", WeavingMode.RUNTIME.name()).toUpperCase();\n\t}\n\t\n    private EnvUtils(){\n\n    }\n\n    public static WeavingMode getWeavingMode() {\n        try {\n            return WeavingMode.valueOf(EnvUtils.WEAVING_MODE);\n        } catch (IllegalArgumentException e) {\n            throw new IllegalArgumentException(\"wrong 'weavingMode' property, supported: \" + Arrays.toString(WeavingMode.values()) + \", actual = \" + EnvUtils.WEAVING_MODE, e);\n        }\n    }\n\n    public static boolean isCompileWeaving() {\n        return WeavingMode.COMPILE == getWeavingMode();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FallbackMethod.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\n\nimport com.google.common.base.Objects;\nimport com.google.common.base.Optional;\nimport com.google.common.base.Supplier;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.command.ExecutionType;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.Validate;\nimport rx.Completable;\n\nimport javax.annotation.Nonnull;\nimport javax.annotation.Nullable;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.flattenTypeVariables;\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.isGenericReturnType;\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.isParametrizedType;\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.isReturnTypeParametrized;\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.isTypeVariable;\nimport static com.netflix.hystrix.contrib.javanica.utils.TypeHelper.isWildcardType;\n\npublic class FallbackMethod {\n\n\n    private final Method method;\n    private final boolean extended;\n    private final boolean defaultFallback;\n    private ExecutionType executionType;\n\n    public static final FallbackMethod ABSENT = new FallbackMethod(null, false, false);\n\n    public FallbackMethod(Method method) {\n        this(method, false, false);\n    }\n\n    public FallbackMethod(Method method, boolean extended, boolean defaultFallback) {\n        this.method = method;\n        this.extended = extended;\n        this.defaultFallback = defaultFallback;\n        if (method != null) {\n            this.executionType = ExecutionType.getExecutionType(method.getReturnType());\n        }\n    }\n\n    public boolean isCommand() {\n        return method.isAnnotationPresent(HystrixCommand.class);\n    }\n\n    public boolean isPresent() {\n        return method != null;\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    public ExecutionType getExecutionType() {\n        return executionType;\n    }\n\n    public boolean isExtended() {\n        return extended;\n    }\n\n    public boolean isDefault() {\n        return defaultFallback;\n    }\n\n    public void validateReturnType(Method commandMethod) throws FallbackDefinitionException {\n        if (isPresent()) {\n            Class<?> commandReturnType = commandMethod.getReturnType();\n            if (ExecutionType.OBSERVABLE == ExecutionType.getExecutionType(commandReturnType)) {\n                if (ExecutionType.OBSERVABLE != getExecutionType()) {\n                    Type commandParametrizedType = commandMethod.getGenericReturnType();\n\n                    // basically any object can be wrapped into Completable, Completable itself ins't parametrized\n                    if(Completable.class.isAssignableFrom(commandMethod.getReturnType())) {\n                        validateCompletableReturnType(commandMethod, method.getReturnType());\n                        return;\n                    }\n\n                    if (isReturnTypeParametrized(commandMethod)) {\n                        commandParametrizedType = getFirstParametrizedType(commandMethod);\n                    }\n                    validateParametrizedType(commandParametrizedType, method.getGenericReturnType(), commandMethod, method);\n                } else {\n                    validateReturnType(commandMethod, method);\n                }\n\n\n            } else if (ExecutionType.ASYNCHRONOUS == ExecutionType.getExecutionType(commandReturnType)) {\n                if (isCommand() && ExecutionType.ASYNCHRONOUS == getExecutionType()) {\n                    validateReturnType(commandMethod, method);\n                }\n                if (ExecutionType.ASYNCHRONOUS != getExecutionType()) {\n                    Type commandParametrizedType = commandMethod.getGenericReturnType();\n                    if (isReturnTypeParametrized(commandMethod)) {\n                        commandParametrizedType = getFirstParametrizedType(commandMethod);\n                    }\n                    validateParametrizedType(commandParametrizedType, method.getGenericReturnType(), commandMethod, method);\n                }\n                if (!isCommand() && ExecutionType.ASYNCHRONOUS == getExecutionType()) {\n                    throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, \"fallback cannot return Future if the fallback isn't command when the command is async.\"));\n                }\n            } else {\n                if (ExecutionType.ASYNCHRONOUS == getExecutionType()) {\n                    throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, \"fallback cannot return Future if command isn't asynchronous.\"));\n                }\n                if (ExecutionType.OBSERVABLE == getExecutionType()) {\n                    throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, \"fallback cannot return Observable if command isn't observable.\"));\n                }\n                validateReturnType(commandMethod, method);\n            }\n\n        }\n    }\n\n    private Type getFirstParametrizedType(Method m) {\n        Type gtype = m.getGenericReturnType();\n        if (gtype instanceof ParameterizedType) {\n            ParameterizedType pType = (ParameterizedType) gtype;\n            return pType.getActualTypeArguments()[0];\n        }\n        return null;\n    }\n\n    // everything can be wrapped into completable except 'void'\n    private void validateCompletableReturnType(Method commandMethod, Class<?> callbackReturnType) {\n        if (Void.TYPE == callbackReturnType) {\n            throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, \"fallback cannot return 'void' if command return type is \" + Completable.class.getSimpleName()));\n        }\n    }\n\n    private void validateReturnType(Method commandMethod, Method fallbackMethod) {\n        if (isGenericReturnType(commandMethod)) {\n            List<Type> commandParametrizedTypes = flattenTypeVariables(commandMethod.getGenericReturnType());\n            List<Type> fallbackParametrizedTypes = flattenTypeVariables(fallbackMethod.getGenericReturnType());\n            Result result = equalsParametrizedTypes(commandParametrizedTypes, fallbackParametrizedTypes);\n            if (!result.success) {\n                List<String> msg = new ArrayList<String>();\n                for (Error error : result.errors) {\n                    Optional<Type> parentKindOpt = getParentKind(error.commandType, commandParametrizedTypes);\n                    String extraHint = \"\";\n                    if (parentKindOpt.isPresent()) {\n                        Type parentKind = parentKindOpt.get();\n                        if (isParametrizedType(parentKind)) {\n                            extraHint = \"--> \" + ((ParameterizedType) parentKind).getRawType().toString() + \"<Ooops!>\\n\";\n                        }\n                    }\n                    msg.add(String.format(error.reason + \"\\n\" + extraHint + \"Command type literal pos: %s; Fallback type literal pos: %s\",\n                            positionAsString(error.commandType, commandParametrizedTypes),\n                            positionAsString(error.fallbackType, fallbackParametrizedTypes)));\n                }\n                throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, StringUtils.join(msg, \"\\n\")));\n            }\n        }\n        validatePlainReturnType(commandMethod, fallbackMethod);\n    }\n\n    private void validatePlainReturnType(Method commandMethod, Method fallbackMethod) {\n        validatePlainReturnType(commandMethod.getReturnType(), fallbackMethod.getReturnType(), commandMethod, fallbackMethod);\n    }\n\n    private void validatePlainReturnType(Class<?> commandReturnType, Class<?> fallbackReturnType, Method commandMethod, Method fallbackMethod) {\n        if (!commandReturnType.isAssignableFrom(fallbackReturnType)) {\n            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, \"Fallback method '\"\n                    + fallbackMethod + \"' must return: \" + commandReturnType + \" or its subclass\"));\n        }\n    }\n\n    private void validateParametrizedType(Type commandReturnType, Type fallbackReturnType, Method commandMethod, Method fallbackMethod) {\n        if (!commandReturnType.equals(fallbackReturnType)) {\n            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, \"Fallback method '\"\n                    + fallbackMethod + \"' must return: \" + commandReturnType + \" or its subclass\"));\n        }\n    }\n\n    private String createErrorMsg(Method commandMethod, Method fallbackMethod, String hint) {\n        return \"Incompatible return types. \\nCommand method: \" + commandMethod + \";\\nFallback method: \" + fallbackMethod + \";\\n\"\n                + (StringUtils.isNotBlank(hint) ? \"Hint: \" + hint : \"\");\n    }\n\n    private static final Result SUCCESS = Result.success();\n\n    private Result equalsParametrizedTypes(List<Type> commandParametrizedTypes, List<Type> fallbackParametrizedTypes) {\n        if (commandParametrizedTypes.size() != fallbackParametrizedTypes.size()) {\n            return Result.failure(Collections.singletonList(\n                    new Error(\"Different size of types variables.\\n\" +\n                            \"Command  type literals size = \" + commandParametrizedTypes.size() + \": \" + commandParametrizedTypes + \"\\n\" +\n                            \"Fallback type literals size = \" + fallbackParametrizedTypes.size() + \": \" + fallbackParametrizedTypes + \"\\n\"\n                    )));\n        }\n\n        for (int i = 0; i < commandParametrizedTypes.size(); i++) {\n            Type commandParametrizedType = commandParametrizedTypes.get(i);\n            Type fallbackParametrizedType = fallbackParametrizedTypes.get(i);\n            Result result = equals(commandParametrizedType, fallbackParametrizedType);\n            if (!result.success) return result;\n        }\n\n        return SUCCESS;\n    }\n\n    // Regular Type#equals method cannot be used to compare parametrized types and type variables\n    // because it compares generic declarations, see java.lang.reflect.GenericDeclaration.\n    // If generic declaration is an instance of java.lang.reflect.Method then command and fallback return types have with different generic declarations which aren't the same.\n    // In this case we need to compare only few type properties, such as bounds for type literal and row types for parametrized types.\n    private static Result equals(Type commandType, Type fallbackType) {\n        if (isParametrizedType(commandType) && isParametrizedType(fallbackType)) {\n            final ParameterizedType pt1 = (ParameterizedType) commandType;\n            final ParameterizedType pt2 = (ParameterizedType) fallbackType;\n            Result result = regularEquals(pt1.getRawType(), pt2.getRawType());\n            return result.andThen(new Supplier<Result>() {\n                @Override\n                public Result get() {\n                    return FallbackMethod.equals(pt1.getActualTypeArguments(), pt2.getActualTypeArguments());\n                }\n            });\n        } else if (isTypeVariable(commandType) && isTypeVariable(fallbackType)) {\n            final TypeVariable tv1 = (TypeVariable) commandType;\n            final TypeVariable tv2 = (TypeVariable) fallbackType;\n            if (tv1.getGenericDeclaration() instanceof Method && tv2.getGenericDeclaration() instanceof Method) {\n                Result result = equals(tv1.getBounds(), tv2.getBounds());\n                return result.append(new Supplier<List<Error>>() {\n                    @Override\n                    public List<Error> get() {\n                        return Collections.singletonList(boundsError(tv1, tv1.getBounds(), \"\", tv2, tv2.getBounds()));\n                    }\n                });\n            }\n            return regularEquals(tv1, tv2);\n        } else if (isWildcardType(commandType) && isWildcardType(fallbackType)) {\n            final WildcardType wt1 = (WildcardType) commandType;\n            final WildcardType wt2 = (WildcardType) fallbackType;\n            Result result = equals(wt1.getLowerBounds(), wt2.getLowerBounds());\n            result = result.append(new Supplier<List<Error>>() {\n                @Override\n                public List<Error> get() {\n                    return Collections.singletonList(boundsError(wt1, wt1.getLowerBounds(), \"lower\", wt2, wt2.getLowerBounds()));\n                }\n            });\n\n            if (result.isFailure()) return result;\n\n            result = equals(wt1.getUpperBounds(), wt2.getUpperBounds());\n            return result.append(new Supplier<List<Error>>() {\n                @Override\n                public List<Error> get() {\n                    return Collections.singletonList(boundsError(wt1, wt1.getUpperBounds(), \"upper\", wt2, wt2.getUpperBounds()));\n                }\n            });\n        } else {\n            return regularEquals(commandType, fallbackType);\n        }\n    }\n\n    private static Result regularEquals(final Type commandType, final Type fallbackType) {\n        return Result.of(Objects.equal(commandType, fallbackType), new Supplier<List<Error>>() {\n            @Override\n            public List<Error> get() {\n                return Collections.singletonList(new Error(\n                        commandType,\n                        String.format(\"Different types. Command type: '%s'; fallback type: '%s'\", commandType, fallbackType),\n                        fallbackType));\n            }\n        });\n    }\n\n    private static Optional<Type> getParentKind(Type type, List<Type> types) {\n        int pos = position(type, types);\n        if (pos <= 0) return Optional.absent();\n        return Optional.of(types.get(pos - 1));\n    }\n\n    private static String positionAsString(Type type, List<Type> types) {\n        int pos = position(type, types);\n        if (pos < 0) {\n            return \"unknown\";\n        }\n        return String.valueOf(pos);\n    }\n\n    private static int position(Type type, List<Type> types) {\n        if (type == null) return -1;\n        if (types == null || types.isEmpty()) return -1;\n        return types.indexOf(type);\n    }\n\n    private static Error boundsError(Type t1, Type[] b1, String boundType, Type t2, Type[] b2) {\n        return new Error(t1,\n                String.format(\"Different %s bounds. Command bounds: '%s'; Fallback bounds: '%s'\",\n                        boundType,\n                        StringUtils.join(b1, \", \"),\n                        StringUtils.join(b2, \", \")),\n                t2);\n    }\n\n    private static Result equals(Type[] t1, Type[] t2) {\n        if (t1 == null && t2 == null) return SUCCESS;\n        if (t1 == null) return Result.failure();\n        if (t2 == null) return Result.failure();\n        if (t1.length != t2.length)\n            return Result.failure(new Error(String.format(\"Different size of type literals. Command size = %d, fallback size = %d\",\n                    t1.length, t2.length)));\n        Result result = SUCCESS;\n        for (int i = 0; i < t1.length; i++) {\n            result = result.combine(equals(t1[i], t2[i]));\n            if (result.isFailure()) return result;\n        }\n        return result;\n    }\n\n    private static class Result {\n        boolean success;\n        List<Error> errors = Collections.emptyList();\n\n        boolean isSuccess() {\n            return success;\n        }\n\n        boolean isFailure() {\n            return !success;\n        }\n\n        static Result of(boolean res, Supplier<List<Error>> errors) {\n            if (res) return success();\n            return failure(errors.get());\n        }\n\n        static Result success() {\n            return new Result(true);\n        }\n\n        static Result failure() {\n            return new Result(false);\n        }\n\n        static Result failure(Error... errors) {\n            return new Result(false, Arrays.asList(errors));\n        }\n\n        static Result failure(List<Error> errors) {\n            return new Result(false, errors);\n        }\n\n        Result combine(Result r) {\n            return new Result(this.success && r.success, merge(this.errors, r.errors));\n        }\n\n        Result andThen(Supplier<Result> resultSupplier) {\n            if (!success) return this;\n            return resultSupplier.get();\n        }\n\n        Result append(List<Error> errors) {\n            if (success) return this;\n            return failure(merge(this.errors, errors));\n        }\n\n        Result append(Supplier<List<Error>> errors) {\n            if (success) return this;\n            return append(errors.get());\n        }\n\n        static List<Error> merge(@Nonnull List<Error> e1, @Nonnull List<Error> e2) {\n            List<Error> res = new ArrayList<Error>(e1.size() + e2.size());\n            res.addAll(e1);\n            res.addAll(e2);\n            return Collections.unmodifiableList(res);\n        }\n\n        Result(boolean success, List<Error> errors) {\n            Validate.notNull(errors, \"errors cannot be null\");\n            this.success = success;\n            this.errors = errors;\n        }\n\n        Result(boolean success) {\n            this.success = success;\n            this.errors = Collections.emptyList();\n        }\n    }\n\n    private static class Error {\n        @Nullable\n        Type commandType;\n        String reason;\n        @Nullable\n        Type fallbackType;\n\n        Error(String reason) {\n            this.reason = reason;\n        }\n\n        Error(Type commandType, String reason, Type fallbackType) {\n            this.commandType = commandType;\n            this.reason = reason;\n            this.fallbackType = fallbackType;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FutureDecorator.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\n\npublic class FutureDecorator implements Future {\n\n    private Future origin;\n\n    public FutureDecorator(Future origin) {\n        this.origin = origin;\n    }\n\n    @Override\n    public boolean cancel(boolean mayInterruptIfRunning) {\n        return origin.cancel(mayInterruptIfRunning);\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return origin.isCancelled();\n    }\n\n    @Override\n    public boolean isDone() {\n        return origin.isDone();\n    }\n\n    @Override\n    public Object get() throws InterruptedException, ExecutionException {\n        Object result = origin.get();\n        if (result instanceof Future) {\n            return ((Future) result).get();\n        }\n        return result;\n    }\n\n    @Override\n    public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {\n        Object result = origin.get(timeout, unit);\n        if (result instanceof Future) {\n            return ((Future) result).get();\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/MethodProvider.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport com.google.common.base.Function;\nimport com.google.common.base.Optional;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.objectweb.asm.ClassReader;\nimport org.objectweb.asm.ClassVisitor;\nimport org.objectweb.asm.MethodVisitor;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static org.objectweb.asm.Opcodes.ACC_BRIDGE;\nimport static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;\nimport static org.objectweb.asm.Opcodes.ASM5;\n\n/**\n * Created by dmgcodevil\n */\npublic final class MethodProvider {\n\n    private MethodProvider() {\n\n    }\n\n    private static final MethodProvider INSTANCE = new MethodProvider();\n\n    public static MethodProvider getInstance() {\n        return INSTANCE;\n    }\n\n    private static final FallbackMethodFinder FALLBACK_METHOD_FINDER = new SpecificFallback(new DefaultCallback());\n\n    private Map<Method, Method> cache = new ConcurrentHashMap<Method, Method>();\n\n    public FallbackMethod getFallbackMethod(Class<?> type, Method commandMethod) {\n        return getFallbackMethod(type, commandMethod, false);\n    }\n\n    /**\n     * Gets fallback method for command method.\n     *\n     * @param enclosingType the enclosing class\n     * @param commandMethod the command method. in the essence it can be a fallback\n     *                      method annotated with HystrixCommand annotation that has a fallback as well.\n     * @param extended      true if the given commandMethod was derived using additional parameter, otherwise - false\n     * @return new instance of {@link FallbackMethod} or {@link FallbackMethod#ABSENT} if there is no suitable fallback method for the given command\n     */\n    public FallbackMethod getFallbackMethod(Class<?> enclosingType, Method commandMethod, boolean extended) {\n        if (commandMethod.isAnnotationPresent(HystrixCommand.class)) {\n            return FALLBACK_METHOD_FINDER.find(enclosingType, commandMethod, extended);\n        }\n        return FallbackMethod.ABSENT;\n    }\n\n    private void getDefaultFallback(){\n\n    }\n\n    private String getClassLevelFallback(Class<?> enclosingClass) {\n        if (enclosingClass.isAnnotationPresent(DefaultProperties.class)) {\n            return enclosingClass.getAnnotation(DefaultProperties.class).defaultFallback();\n        }\n        return StringUtils.EMPTY;\n    }\n\n    private static class SpecificFallback extends FallbackMethodFinder {\n\n        public SpecificFallback(FallbackMethodFinder next) {\n            super(next);\n        }\n\n        @Override\n        boolean isSpecific() {\n            return true;\n        }\n\n        @Override\n        public String getFallbackName(Class<?> enclosingType, Method commandMethod) {\n            return commandMethod.getAnnotation(HystrixCommand.class).fallbackMethod();\n        }\n\n        @Override\n        boolean canHandle(Class<?> enclosingType, Method commandMethod) {\n            return StringUtils.isNotBlank(getFallbackName(enclosingType, commandMethod));\n        }\n    }\n\n    private static class DefaultCallback extends FallbackMethodFinder {\n        @Override\n        boolean isDefault() {\n            return true;\n        }\n\n        @Override\n        public String getFallbackName(Class<?> enclosingType, Method commandMethod) {\n            String commandDefaultFallback = commandMethod.getAnnotation(HystrixCommand.class).defaultFallback();\n            String classDefaultFallback = Optional.fromNullable(enclosingType.getAnnotation(DefaultProperties.class))\n                    .transform(new Function<DefaultProperties, String>() {\n                        @Override\n                        public String apply(DefaultProperties input) {\n                            return input.defaultFallback();\n                        }\n                    }).or(StringUtils.EMPTY);\n\n            return StringUtils.defaultIfEmpty(commandDefaultFallback, classDefaultFallback);\n        }\n\n        @Override\n        boolean canHandle(Class<?> enclosingType, Method commandMethod) {\n            return StringUtils.isNotBlank(getFallbackName(enclosingType, commandMethod));\n        }\n    }\n\n    private static abstract class FallbackMethodFinder {\n        FallbackMethodFinder next;\n\n        public FallbackMethodFinder() {\n        }\n\n        public FallbackMethodFinder(FallbackMethodFinder next) {\n            this.next = next;\n        }\n\n        boolean isDefault() {\n            return false;\n        }\n\n        boolean isSpecific(){\n            return false;\n        }\n\n        public abstract String getFallbackName(Class<?> enclosingType, Method commandMethod);\n\n        public FallbackMethod find(Class<?> enclosingType, Method commandMethod, boolean extended) {\n            if (canHandle(enclosingType, commandMethod)) {\n                return doFind(enclosingType, commandMethod, extended);\n            } else if (next != null) {\n                return next.find(enclosingType, commandMethod, extended);\n            } else {\n                return FallbackMethod.ABSENT;\n            }\n        }\n\n        abstract boolean canHandle(Class<?> enclosingType, Method commandMethod);\n\n        private FallbackMethod doFind(Class<?> enclosingType, Method commandMethod, boolean extended) {\n            String name = getFallbackName(enclosingType, commandMethod);\n            Class<?>[] fallbackParameterTypes = null;\n            if (isDefault()) {\n                fallbackParameterTypes = new Class[0];\n            } else {\n                fallbackParameterTypes = commandMethod.getParameterTypes();\n            }\n\n            if (extended && fallbackParameterTypes[fallbackParameterTypes.length - 1] == Throwable.class) {\n                fallbackParameterTypes = ArrayUtils.remove(fallbackParameterTypes, fallbackParameterTypes.length - 1);\n            }\n\n            Class<?>[] extendedFallbackParameterTypes = Arrays.copyOf(fallbackParameterTypes,\n                    fallbackParameterTypes.length + 1);\n            extendedFallbackParameterTypes[fallbackParameterTypes.length] = Throwable.class;\n\n            Optional<Method> exFallbackMethod = getMethod(enclosingType, name, extendedFallbackParameterTypes);\n            Optional<Method> fMethod = getMethod(enclosingType, name, fallbackParameterTypes);\n            Method method = exFallbackMethod.or(fMethod).orNull();\n            if (method == null) {\n                throw new FallbackDefinitionException(\"fallback method wasn't found: \" + name + \"(\" + Arrays.toString(fallbackParameterTypes) + \")\");\n            }\n            return new FallbackMethod(method, exFallbackMethod.isPresent(), isDefault());\n        }\n\n    }\n\n\n    /**\n     * Gets method by name and parameters types using reflection,\n     * if the given type doesn't contain required method then continue applying this method for all super classes up to Object class.\n     *\n     * @param type           the type to search method\n     * @param name           the method name\n     * @param parameterTypes the parameters types\n     * @return Some if method exists otherwise None\n     */\n    public static Optional<Method> getMethod(Class<?> type, String name, Class<?>... parameterTypes) {\n        Method[] methods = type.getDeclaredMethods();\n        for (Method method : methods) {\n            if (method.getName().equals(name) && Arrays.equals(method.getParameterTypes(), parameterTypes)) {\n                return Optional.of(method);\n            }\n        }\n        Class<?> superClass = type.getSuperclass();\n        if (superClass != null && !superClass.equals(Object.class)) {\n            return getMethod(superClass, name, parameterTypes);\n        } else {\n            return Optional.absent();\n        }\n    }\n\n    /**\n     * Finds generic method for the given bridge method.\n     *\n     * @param bridgeMethod the bridge method\n     * @param aClass       the type where the bridge method is declared\n     * @return generic method\n     * @throws IOException\n     * @throws NoSuchMethodException\n     * @throws ClassNotFoundException\n     */\n    public Method unbride(final Method bridgeMethod, Class<?> aClass) throws IOException, NoSuchMethodException, ClassNotFoundException {\n        if (bridgeMethod.isBridge() && bridgeMethod.isSynthetic()) {\n            if (cache.containsKey(bridgeMethod)) {\n                return cache.get(bridgeMethod);\n            }\n\n            ClassReader classReader = new ClassReader(aClass.getName());\n            final MethodSignature methodSignature = new MethodSignature();\n            classReader.accept(new ClassVisitor(ASM5) {\n                @Override\n                public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {\n                    boolean bridge = (access & ACC_BRIDGE) != 0 && (access & ACC_SYNTHETIC) != 0;\n                    if (bridge && bridgeMethod.getName().equals(name) && getParameterCount(desc) == bridgeMethod.getParameterTypes().length) {\n                        return new MethodFinder(methodSignature);\n                    }\n                    return super.visitMethod(access, name, desc, signature, exceptions);\n                }\n            }, 0);\n            Method method = aClass.getDeclaredMethod(methodSignature.name, methodSignature.getParameterTypes());\n            cache.put(bridgeMethod, method);\n            return method;\n\n        } else {\n            return bridgeMethod;\n        }\n    }\n\n    private static int getParameterCount(String desc) {\n        return parseParams(desc).length;\n    }\n\n    private static String[] parseParams(String desc) {\n        String params = desc.split(\"\\\\)\")[0].replace(\"(\", \"\");\n        if (params.length() == 0) {\n            return new String[0];\n        }\n        return params.split(\";\");\n    }\n\n    private static class MethodSignature {\n        String name;\n        String desc;\n\n        public Class<?>[] getParameterTypes() throws ClassNotFoundException {\n            if (desc == null) {\n                return new Class[0];\n            }\n            String[] params = parseParams(desc);\n            Class<?>[] parameterTypes = new Class[params.length];\n\n            for (int i = 0; i < params.length; i++) {\n                String arg = params[i].substring(1).replace(\"/\", \".\");\n                parameterTypes[i] = Class.forName(arg);\n            }\n            return parameterTypes;\n        }\n    }\n\n    private static class MethodFinder extends MethodVisitor {\n        private MethodSignature methodSignature;\n\n        public MethodFinder(MethodSignature methodSignature) {\n            super(ASM5);\n            this.methodSignature = methodSignature;\n        }\n\n        @Override\n        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {\n            methodSignature.name = name;\n            methodSignature.desc = desc;\n            super.visitMethodInsn(opcode, owner, name, desc, itf);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/TypeHelper.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils;\n\nimport com.google.common.collect.TreeTraverser;\nimport org.apache.commons.lang3.Validate;\n\nimport javax.annotation.ParametersAreNonnullByDefault;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Helper class that provides convenient methods to work with java types.\n * <p/>\n * Created by dmgcodevil.\n */\npublic final class TypeHelper {\n    private TypeHelper() {\n    }\n\n\n    public static boolean isGenericReturnType(Method method) {\n        return isParametrizedType(method.getGenericReturnType()) || isTypeVariable(method.getGenericReturnType());\n    }\n\n    /**\n     * Check whether return type of the given method is parametrized or not.\n     *\n     * @param method the method\n     * @return true - if return type is {@link ParameterizedType}, otherwise - false\n     */\n    public static boolean isReturnTypeParametrized(Method method) {\n        return isParametrizedType(method.getGenericReturnType());\n    }\n\n    public static boolean isParametrizedType(Type t) {\n        return t instanceof ParameterizedType;\n    }\n\n    public static boolean isTypeVariable(Type t) {\n        return t instanceof TypeVariable;\n    }\n\n    public static boolean isWildcardType(Type t) {\n        return t instanceof WildcardType;\n    }\n\n    /**\n     * Unwinds parametrized type into plain list that contains all parameters for the given type including nested parameterized types,\n     * for example calling the method for the following type\n     * <code>\n     * GType<GType<GDoubleType<GType<GDoubleType<Parent, Parent>>, Parent>>>\n     * </code>\n     * will return list of 8 elements:\n     * <code>\n     * [GType, GType, GDoubleType, GType, GDoubleType, Parent, Parent, Parent]\n     * </code>\n     * if the given type is not parametrized then returns list with one element which is given type passed into method.\n     *\n     * @param type the parameterized type\n     * @return list of {@link Type}\n     */\n    @ParametersAreNonnullByDefault\n    public static List<Type> flattenTypeVariables(Type type) {\n        Validate.notNull(type, \"type cannot be null\");\n        List<Type> types = new ArrayList<Type>();\n        TreeTraverser<Type> typeTraverser = new TreeTraverser<Type>() {\n            @Override\n            public Iterable<Type> children(Type root) {\n                if (root instanceof ParameterizedType) {\n                    ParameterizedType pType = (ParameterizedType) root;\n                    return Arrays.asList(pType.getActualTypeArguments());\n                } else if (root instanceof TypeVariable) {\n                    TypeVariable pType = (TypeVariable) root;\n                    return Arrays.asList(pType.getBounds());\n                }\n                return Collections.emptyList();\n            }\n        };\n        for (Type t : typeTraverser.breadthFirstTraversal(type)) {\n            types.add(t);\n        }\n        return types;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/ajc/AjcUtils.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.utils.ajc;\n\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport org.aspectj.lang.reflect.MethodSignature;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\n\n/**\n * Created by dmgcodevil\n */\npublic final class AjcUtils {\n\n    private AjcUtils() {\n        throw new UnsupportedOperationException(\"it's prohibited to create instances of this class\");\n    }\n\n\n    public static Method getAjcMethod(final Class<?> target, final String methodName, final AdviceType adviceType, final Class<?>... pTypes) {\n        for (Method method : target.getDeclaredMethods()) {\n            if (method.getName().startsWith(methodName + adviceType.getPostfix())\n                    && Modifier.isFinal(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) {\n                Class<?>[] parameterTypes = method.getParameterTypes();\n                if (pTypes.length == 0 && parameterTypes.length == 0) {\n                    return method;\n                }\n                if (pTypes.length == parameterTypes.length - 2) {\n                    boolean match = true;\n                    Class<?>[] origParamTypes = removeAspectjArgs(parameterTypes);\n                    int index = 0;\n                    for (Class<?> pType : origParamTypes) {\n                        Class<?> expected = pTypes[index++];\n                        if (pType != expected) {\n                            match = false;\n                        }\n                    }\n                    if (match) {\n                        return method;\n                    }\n                }\n            }\n        }\n        if (target.getSuperclass() != null) {\n            return getAjcMethod(target.getSuperclass(), methodName, adviceType, pTypes);\n        }\n\n        return null;\n    }\n\n    public static Method getAjcMethodAroundAdvice(final Class<?> target, final String methodName, final Class<?>... pTypes) {\n        return getAjcMethod(target, methodName, AdviceType.Around, pTypes);\n    }\n\n\n    public static Method getAjcMethodAroundAdvice(Class<?> target, MethodSignature signature) {\n        return getAjcMethodAroundAdvice(target, signature.getMethod().getName(), signature.getParameterTypes());\n    }\n\n\n    public static Method getAjcMethodAroundAdvice(Class<?> target, Method method) {\n        return getAjcMethodAroundAdvice(target, method.getName(), method.getParameterTypes());\n    }\n\n\n    public static Object invokeAjcMethod(Method method, Object target, MetaHolder metaHolder, Object... args) throws InvocationTargetException, IllegalAccessException {\n        method.setAccessible(true);\n        Object[] extArgs = new Object[args.length + 2];\n        extArgs[0] = target;\n        System.arraycopy(args, 0, extArgs, 1, args.length);\n        extArgs[extArgs.length - 1] = metaHolder.getJoinPoint();\n        return method.invoke(target, extArgs);\n    }\n\n    private static Class<?>[] removeAspectjArgs(Class<?>[] parameterTypes) {\n        Class<?>[] origParamTypes = new Class[parameterTypes.length - 2];\n        System.arraycopy(parameterTypes, 1, origParamTypes, 0, parameterTypes.length - 2);\n        return origParamTypes;\n    }\n\n    public enum AdviceType {\n        Around(\"_aroundBody\");\n        private String postfix;\n\n        AdviceType(String postfix) {\n            this.postfix = postfix;\n        }\n\n        public String getPostfix() {\n            return postfix;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/main/resources/dummy.txt",
    "content": "====\n    Copyright 2016 Netflix, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n====\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationContextFactoryTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\nimport com.google.common.base.Predicate;\nimport com.google.common.collect.Iterables;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport com.netflix.hystrix.contrib.javanica.exception.HystrixCachingException;\nimport org.junit.Test;\n\n\nimport java.lang.annotation.Annotation;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Unit test for {@link CacheInvocationContextFactory}.\n *\n * @author dmgcodevil\n */\npublic class CacheInvocationContextFactoryTest {\n\n    @Test\n    public void testCreateCacheResultInvocationContext_givenMethodAnnotatedWithCacheResult_shouldCreateCorrectCacheKeyInvocationContext()\n            throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String param1 = \"val_1\";\n        String param2 = \"val_2\";\n        Integer param3 = 3;\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethod\", String.class, String.class, Integer.class))\n                .args(new Object[]{param1, param2, param3})\n                .obj(testCacheClass).build();\n        // when\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n\n        // then\n        assertNotNull(context.getKeyParameters());\n        assertEquals(2, context.getKeyParameters().size());\n        assertEquals(String.class, context.getKeyParameters().get(0).getRawType());\n        assertEquals(0, context.getKeyParameters().get(0).getPosition());\n        assertEquals(param1, context.getKeyParameters().get(0).getValue());\n        assertTrue(isAnnotationPresent(context.getKeyParameters().get(0), CacheKey.class));\n\n        assertEquals(Integer.class, context.getKeyParameters().get(1).getRawType());\n        assertEquals(2, context.getKeyParameters().get(1).getPosition());\n        assertEquals(param3, context.getKeyParameters().get(1).getValue());\n        assertTrue(isAnnotationPresent(context.getKeyParameters().get(1), CacheKey.class));\n    }\n\n    @Test\n    public void testCreateCacheRemoveInvocationContext_givenMethodAnnotatedWithCacheRemove_shouldCreateCorrectCacheKeyInvocationContext()\n            throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String param1 = \"val_1\";\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheRemoveMethod\", String.class))\n                .args(new Object[]{param1})\n                .obj(testCacheClass).build();\n        // when\n        CacheInvocationContext<CacheRemove> context = CacheInvocationContextFactory.createCacheRemoveInvocationContext(metaHolder);\n\n        // then\n        assertNotNull(context.getKeyParameters());\n        assertEquals(1, context.getKeyParameters().size());\n        CacheInvocationParameter actual = context.getKeyParameters().get(0);\n        assertEquals(String.class, actual.getRawType());\n        assertEquals(param1, actual.getValue());\n        assertEquals(0, actual.getPosition());\n    }\n\n    @Test(expected = HystrixCachingException.class)\n    public void testCacheResultMethodWithWrongCacheKeyMethodSignature_givenWrongCacheKeyMethod_shouldThrowException() throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String param1 = \"val_1\";\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethodWithWrongCacheKeyMethodSignature\", String.class))\n                .args(new Object[]{param1})\n                .obj(testCacheClass).build();\n        // when\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n        // then expected HystrixCachingException\n    }\n\n    @Test(expected = HystrixCachingException.class)\n    public void testCacheResultMethodWithCacheKeyMethodWithWrongReturnType_givenCacheKeyMethodWithWrongReturnType_shouldThrowException() throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String param1 = \"val_1\";\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethodWithCacheKeyMethodWithWrongReturnType\", String.class, String.class))\n                .args(new Object[]{param1})\n                .obj(testCacheClass).build();\n        // when\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n        System.out.println(context);\n        // then expected HystrixCachingException\n    }\n\n    public static class TestCacheClass {\n\n        @CacheResult\n        public Object cacheResultMethod(@CacheKey String param1, String param2, @CacheKey Integer param3) {\n            return null;\n        }\n\n        @CacheRemove(commandKey = \"test\")\n        public Object cacheRemoveMethod(String param1) {\n            return null;\n        }\n\n        @CacheResult(cacheKeyMethod = \"cacheKeyMethodSignature\")\n        public Object cacheResultMethodWithWrongCacheKeyMethodSignature(String param2) {\n            return null;\n        }\n\n        private String cacheKeyMethodSignature(String param1, String param2) {\n            return null;\n        }\n\n        @CacheResult(cacheKeyMethod = \"cacheKeyMethodWithWrongReturnType\")\n        public Object cacheResultMethodWithCacheKeyMethodWithWrongReturnType(String param1, String param2) {\n            return null;\n        }\n\n        private Long cacheKeyMethodWithWrongReturnType(String param1, String param2) {\n            return null;\n        }\n    }\n\n    private static boolean isAnnotationPresent(CacheInvocationParameter parameter, final Class<?> annotation) {\n        return Iterables.tryFind(parameter.getAnnotations(), new Predicate<Annotation>() {\n            @Override\n            public boolean apply(Annotation input) {\n                return input.annotationType().equals(annotation);\n            }\n        }).isPresent();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationParameterTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\n\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\nimport org.junit.Test;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\npublic class CacheInvocationParameterTest {\n\n    @Test\n    public void testCacheInvocationParameterConstructor() throws NoSuchMethodException {\n        // given\n        Class<?> rawType = String.class;\n        Object value = \"test\";\n        Method method = CacheInvocationParameterTest.class.getDeclaredMethod(\"stabMethod\", String.class);\n        method.setAccessible(true);\n        Annotation[] annotations = method.getParameterAnnotations()[0];\n        int position = 0;\n        // when\n        CacheInvocationParameter cacheInvocationParameter = new CacheInvocationParameter(rawType, value, annotations, position);\n        // then\n        assertEquals(rawType, cacheInvocationParameter.getRawType());\n        assertEquals(value, cacheInvocationParameter.getValue());\n        assertEquals(annotations[0], cacheInvocationParameter.getCacheKeyAnnotation());\n        assertTrue(cacheInvocationParameter.hasCacheKeyAnnotation());\n        assertTrue(cacheInvocationParameter.getAnnotations().contains(annotations[0]));\n\n        try {\n            cacheInvocationParameter.getAnnotations().clear();\n            fail();\n        } catch (Throwable e) {\n            // getAnnotations should return immutable set.\n        }\n    }\n\n    private static void stabMethod(@CacheKey String val) {\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/cache/HystrixCacheKeyGeneratorTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.cache;\n\n\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.command.MetaHolder;\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class HystrixCacheKeyGeneratorTest {\n\n    @Test\n    public void testGenerateCacheKey_givenUser_shouldReturnCorrectCacheKey() throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String id = \"1\";\n        User user = new User();\n        user.setId(id);\n        Profile profile = new Profile(\"user name\");\n        user.setProfile(profile);\n        String expectedKey = id + user.getProfile().getName();\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethod\", String.class, User.class))\n                .args(new Object[]{id, user})\n                .obj(testCacheClass).build();\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n        HystrixCacheKeyGenerator keyGenerator = HystrixCacheKeyGenerator.getInstance();\n        // when\n        String actual = keyGenerator.generateCacheKey(context).getCacheKey();\n        // then\n        assertEquals(expectedKey, actual);\n    }\n\n    @Test\n    public void testGenerateCacheKey_givenUserWithNullProfile_shouldReturnCorrectCacheKey() throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        String id = \"1\";\n        User user = new User();\n        user.setId(id);\n        user.setProfile(null);\n        String expectedKey = id;\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethod\", String.class, User.class))\n                .args(new Object[]{id, user})\n                .obj(testCacheClass).build();\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n        HystrixCacheKeyGenerator keyGenerator = HystrixCacheKeyGenerator.getInstance();\n        // when\n        String actual = keyGenerator.generateCacheKey(context).getCacheKey();\n        // then\n        assertEquals(expectedKey, actual);\n    }\n\n    @Test\n    public void testGenerateCacheKey_givenCacheKeyMethodWithNoArguments_shouldReturnEmptyCacheKey() throws NoSuchMethodException {\n        // given\n        TestCacheClass testCacheClass = new TestCacheClass();\n        MetaHolder metaHolder = MetaHolder.builder()\n                .method(TestCacheClass.class.getMethod(\"cacheResultMethod\"))\n                .args(new Object[]{})\n                .obj(testCacheClass).build();\n        CacheInvocationContext<CacheResult> context = CacheInvocationContextFactory.createCacheResultInvocationContext(metaHolder);\n        HystrixCacheKeyGenerator keyGenerator = HystrixCacheKeyGenerator.getInstance();\n        // when\n        HystrixGeneratedCacheKey actual = keyGenerator.generateCacheKey(context);\n        // then\n        assertEquals(DefaultHystrixGeneratedCacheKey.EMPTY, actual);\n    }\n\n    public static class TestCacheClass {\n\n        @CacheResult\n        public Object cacheResultMethod(@CacheKey String id, @CacheKey(\"profile.name\") User user) {\n            return \"test\";\n        }\n\n        @CacheResult\n        public Object cacheResultMethod() {\n            return \"test\";\n        }\n\n    }\n\n    public static class User {\n        private String id;\n        private Profile profile;\n\n        public String getId() {\n            return id;\n        }\n\n        public void setId(String id) {\n            this.id = id;\n        }\n\n        public Profile getProfile() {\n            return profile;\n        }\n\n        public void setProfile(Profile profile) {\n            this.profile = profile;\n        }\n    }\n\n    public static class Profile {\n        private String name;\n\n        public Profile() {\n        }\n\n        public Profile(String name) {\n            this.name = name;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/command/ExecutionTypeTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.command;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport rx.Observable;\nimport rx.internal.operators.OperatorMulticast;\n\nimport java.util.List;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.RunnableFuture;\n\nimport static com.netflix.hystrix.contrib.javanica.command.ExecutionType.ASYNCHRONOUS;\nimport static com.netflix.hystrix.contrib.javanica.command.ExecutionType.OBSERVABLE;\nimport static com.netflix.hystrix.contrib.javanica.command.ExecutionType.SYNCHRONOUS;\nimport static java.util.Arrays.asList;\nimport static org.junit.Assert.assertEquals;\n\n@RunWith(Parameterized.class)\npublic class ExecutionTypeTest {\n\n    @Parameterized.Parameters\n    public static List<Object[]> data() {\n        return asList(new Object[][]{\n                {returnType(Integer.class), shouldHaveExecutionType(SYNCHRONOUS)},\n                {returnType(List.class), shouldHaveExecutionType(SYNCHRONOUS)},\n                {returnType(Object.class), shouldHaveExecutionType(SYNCHRONOUS)},\n                {returnType(Class.class), shouldHaveExecutionType(SYNCHRONOUS)},\n                {returnType(Future.class), shouldHaveExecutionType(ASYNCHRONOUS)},\n                {returnType(AsyncResult.class), shouldHaveExecutionType(ASYNCHRONOUS)},\n                {returnType(RunnableFuture.class), shouldHaveExecutionType(ASYNCHRONOUS)},\n                {returnType(Observable.class), shouldHaveExecutionType(OBSERVABLE)},\n                {returnType(OperatorMulticast.class), shouldHaveExecutionType(OBSERVABLE)},\n        });\n    }\n\n    @Test\n    public void should_return_correct_execution_type() throws Exception {\n        assertEquals(\"Unexpected execution type for method return type: \" + methodReturnType, expectedType, ExecutionType.getExecutionType(methodReturnType));\n\n    }\n\n    private static ExecutionType shouldHaveExecutionType(final ExecutionType type) {\n        return type;\n    }\n\n    private static Class<?> returnType(final Class<?> aClass) {\n        return aClass;\n    }\n\n    private final Class<?> methodReturnType;\n    private final ExecutionType expectedType;\n\n    public ExecutionTypeTest(final Class<?> methodReturnType, final ExecutionType expectedType) {\n        this.methodReturnType = methodReturnType;\n        this.expectedType = expectedType;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/BasicHystrixTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common;\n\nimport com.google.common.base.Throwables;\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.Rule;\n\nimport java.lang.reflect.Field;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicHystrixTest {\n    @Rule\n    public HystrixRequestContextRule request = new HystrixRequestContextRule();\n\n    protected final HystrixRequestContext getHystrixContext() {\n        return request.context();\n    }\n\n    protected void resetContext() {\n        request.reset();\n    }\n\n    protected final HystrixThreadPoolProperties getThreadPoolProperties(HystrixInvokableInfo<?> command) {\n        try {\n            Field field = command.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField(\"threadPool\");\n            field.setAccessible(true);\n            HystrixThreadPool threadPool = (HystrixThreadPool) field.get(command);\n\n            Field field2 = HystrixThreadPool.HystrixThreadPoolDefault.class.getDeclaredField(\"properties\");\n            field2.setAccessible(true);\n            return (HystrixThreadPoolProperties) field2.get(threadPool);\n\n        } catch (NoSuchFieldException e) {\n            throw Throwables.propagate(e);\n        } catch (IllegalAccessException e) {\n            throw Throwables.propagate(e);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/CommonUtils.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common;\n\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Iterables;\nimport com.google.common.collect.Lists;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\n\nimport javax.annotation.Nullable;\nimport java.util.Collection;\nimport java.util.List;\n\nimport static org.junit.Assert.assertTrue;\n\npublic class CommonUtils {\n\n    public HystrixCommandMetrics getMetrics(String commandKey) {\n        return HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(commandKey));\n    }\n\n\n    public static HystrixInvokableInfo<?> getLastExecutedCommand() {\n        Collection<HystrixInvokableInfo<?>> executedCommands =\n                HystrixRequestLog.getCurrentRequest().getAllExecutedCommands();\n        return Iterables.getLast(executedCommands);\n    }\n\n    public static void assertExecutedCommands(String... commands) {\n        Collection<HystrixInvokableInfo<?>> executedCommands =\n                HystrixRequestLog.getCurrentRequest().getAllExecutedCommands();\n\n        List<String> executedCommandsKeys = getExecutedCommandsKeys(Lists.newArrayList(executedCommands));\n\n        for (String cmd : commands) {\n            assertTrue(\"command: '\" + cmd + \"' wasn't executed\", executedCommandsKeys.contains(cmd));\n        }\n    }\n\n    public static List<String> getExecutedCommandsKeys() {\n        Collection<HystrixInvokableInfo<?>> executedCommands =\n                HystrixRequestLog.getCurrentRequest().getAllExecutedCommands();\n\n        return getExecutedCommandsKeys(Lists.newArrayList(executedCommands));\n    }\n\n    public static List<String> getExecutedCommandsKeys(List<HystrixInvokableInfo<?>> executedCommands) {\n        return Lists.transform(executedCommands, new Function<HystrixInvokableInfo<?>, String>() {\n            @Nullable\n            @Override\n            public String apply(@Nullable HystrixInvokableInfo<?> input) {\n                return input.getCommandKey().name();\n            }\n        });\n    }\n\n    public static HystrixInvokableInfo getHystrixCommandByKey(String key) {\n        HystrixInvokableInfo hystrixCommand = null;\n        Collection<HystrixInvokableInfo<?>> executedCommands =\n                HystrixRequestLog.getCurrentRequest().getAllExecutedCommands();\n        for (HystrixInvokableInfo command : executedCommands) {\n            if (command.getCommandKey().name().equals(key)) {\n                hystrixCommand = command;\n                break;\n            }\n        }\n        return hystrixCommand;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/cache/BasicCacheTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.cache;\n\nimport com.google.common.base.Predicate;\nimport com.google.common.collect.Iterables;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;\nimport com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;\nimport com.netflix.hystrix.contrib.javanica.exception.HystrixCachingException;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.Profile;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport javax.annotation.PostConstruct;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getLastExecutedCommand;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicCacheTest extends BasicHystrixTest {\n\n    private UserService userService;\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n    }\n\n    protected abstract UserService createUserService();\n\n    /**\n     * Get-Set-Get with Request Cache Invalidation Test.\n     * <p/>\n     * given:\n     * command to get user by id, see {@link UserService#getUserById(String)}\n     * command to update user, see {@link UserService#update(com.netflix.hystrix.contrib.javanica.test.common.domain.User)}\n     * <p/>\n     * when:\n     * 1. call {@link UserService#getUserById(String)}\n     * 2. call {@link UserService#getUserById(String)}\n     * 3. call {@link UserService#update(com.netflix.hystrix.contrib.javanica.test.common.domain.User)}\n     * 4. call {@link UserService#getUserById(String)}\n     * <p/>\n     * then:\n     * at the first time \"getUserById\" command shouldn't retrieve value from cache\n     * at the second time \"getUserById\" command should retrieve value from cache\n     * \"update\" method should update an user and flush cache related to \"getUserById\" command\n     * after \"update\" method execution \"getUserById\" command shouldn't retrieve value from cache\n     */\n    @Test\n    public void testGetSetGetUserCache_givenTwoCommands() {\n\n        User user = userService.getUserById(\"1\");\n        HystrixInvokableInfo<?> getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command with\n        // the value of \"1\" so it should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"name\", user.getName()); // initial name value\n\n        user = userService.getUserById(\"1\");\n        assertEquals(\"1\", user.getId());\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the second time we've executed this command with\n        // the same value so it should return from cache\n        assertTrue(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"name\", user.getName()); // same name\n\n        // create new user with same id but with new name\n        user = new User(\"1\", \"new_name\");\n        userService.update(user); // update the user\n\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command after \"update\"\n        // method was invoked and a cache for \"getUserById\" command was flushed\n        // so the response should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"new_name\", user.getName());\n\n        // start a new request context\n        resetContext();\n\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        assertEquals(\"1\", user.getId());\n        // this is a new request context so this\n        // should not come from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n\n    }\n\n    @Test\n    public void testGetSetGetUserCache_givenGetUserByEmailAndUpdateProfile() {\n        User user = userService.getUserByEmail(\"email\");\n        HystrixInvokableInfo<?> getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command with\n        // the value of \"1\" so it should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"name\", user.getName());\n        assertEquals(\"email\", user.getProfile().getEmail()); // initial email value\n\n        user = userService.getUserByEmail(\"email\");\n        assertEquals(\"1\", user.getId());\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the second time we've executed this command with\n        // the same value so it should return from cache\n        assertTrue(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"email\", user.getProfile().getEmail()); // same email\n\n        // create new user with same id but with new email\n        Profile profile = new Profile();\n        profile.setEmail(\"new_email\");\n        user.setProfile(profile);\n        userService.updateProfile(user); // update the user profile\n\n        user = userService.getUserByEmail(\"new_email\");\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command after \"updateProfile\"\n        // method was invoked and a cache for \"getUserByEmail\" command was flushed\n        // so the response should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"name\", user.getName());\n        assertEquals(\"new_email\", user.getProfile().getEmail());\n\n        // start a new request context\n        resetContext();\n\n        user = userService.getUserByEmail(\"new_email\");\n        getUserByIdCommand = getLastExecutedCommand();\n        assertEquals(\"1\", user.getId());\n        // this is a new request context so this\n        // should not come from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n    }\n\n    @Test\n    public void testGetSetGetUserCache_givenOneCommandAndOneMethodAnnotatedWithCacheRemove() {\n        // given\n        User user = userService.getUserById(\"1\");\n        HystrixInvokableInfo<?> getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command with\n        // the value of \"1\" so it should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"name\", user.getName()); // initial name value\n\n        user = userService.getUserById(\"1\");\n        assertEquals(\"1\", user.getId());\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the second time we've executed this command with\n        // the same value so it should return from cache\n        assertTrue(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"name\", user.getName()); // same name\n\n        // when\n        userService.updateName(\"1\", \"new_name\"); // update the user name\n\n        // then\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        // this is the first time we've executed this command after \"update\"\n        // method was invoked and a cache for \"getUserById\" command was flushed\n        // so the response should not be from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n        assertEquals(\"1\", user.getId());\n        assertEquals(\"new_name\", user.getName());\n\n        // start a new request context\n        resetContext();\n        user = userService.getUserById(\"1\");\n        getUserByIdCommand = getLastExecutedCommand();\n        assertEquals(\"1\", user.getId());\n        // this is a new request context so this\n        // should not come from cache\n        assertFalse(getUserByIdCommand.isResponseFromCache());\n    }\n\n\n    @Test(expected = HystrixCachingException.class)\n    public void testGetUser_givenWrongCacheKeyMethodReturnType_shouldThrowException() {\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            User user = userService.getUserByName(\"name\");\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    @Test(expected = HystrixCachingException.class)\n    public void testGetUserByName_givenNonexistentCacheKeyMethod_shouldThrowException() {\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            User user = userService.getUser();\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    public static class UserService {\n        private Map<String, User> storage = new ConcurrentHashMap<String, User>();\n\n        @PostConstruct\n        public void init() {\n            User user = new User(\"1\", \"name\");\n            Profile profile = new Profile();\n            profile.setEmail(\"email\");\n            user.setProfile(profile);\n            storage.put(\"1\", user);\n        }\n\n        @CacheResult\n        @HystrixCommand\n        public User getUserById(@CacheKey String id) {\n            return storage.get(id);\n        }\n\n        @CacheResult(cacheKeyMethod = \"getUserByNameCacheKey\")\n        @HystrixCommand\n        public User getUserByName(String name) {\n            return null;\n        }\n\n        private Long getUserByNameCacheKey() {\n            return 0L;\n        }\n\n        @CacheResult(cacheKeyMethod = \"nonexistent\")\n        @HystrixCommand\n        public User getUser() {\n            return null;\n        }\n\n        @CacheResult(cacheKeyMethod = \"getUserByEmailCacheKey\")\n        @HystrixCommand\n        public User getUserByEmail(final String email) {\n            return Iterables.tryFind(storage.values(), new Predicate<User>() {\n                @Override\n                public boolean apply(User input) {\n                    return input.getProfile().getEmail().equalsIgnoreCase(email);\n                }\n            }).orNull();\n        }\n\n        private String getUserByEmailCacheKey(String email) {\n            return email;\n        }\n\n        @CacheRemove(commandKey = \"getUserById\")\n        @HystrixCommand\n        public void update(@CacheKey(\"id\") User user) {\n            storage.put(user.getId(), user);\n        }\n\n        @CacheRemove(commandKey = \"getUserByEmail\")\n        @HystrixCommand\n        public void updateProfile(@CacheKey(\"profile.email\") User user) {\n            storage.get(user.getId()).setProfile(user.getProfile());\n        }\n\n        @CacheRemove(commandKey = \"getUserById\")\n        public void updateName(@CacheKey String id, String name) {\n            storage.get(id).setName(name);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/collapser/BasicCollapserTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.collapser;\n\nimport com.google.common.collect.Sets;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicCollapserTest extends BasicHystrixTest {\n\n    protected abstract UserService createUserService();\n\n    private UserService userService;\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n\n    }\n\n    @Test\n    public void testGetUserById() throws ExecutionException, InterruptedException {\n\n        Future<User> f1 = userService.getUserById(\"1\");\n        Future<User> f2 = userService.getUserById(\"2\");\n        Future<User> f3 = userService.getUserById(\"3\");\n        Future<User> f4 = userService.getUserById(\"4\");\n        Future<User> f5 = userService.getUserById(\"5\");\n\n        assertEquals(\"name: 1\", f1.get().getName());\n        assertEquals(\"name: 2\", f2.get().getName());\n        assertEquals(\"name: 3\", f3.get().getName());\n        assertEquals(\"name: 4\", f4.get().getName());\n        assertEquals(\"name: 5\", f5.get().getName());\n        // assert that the batch command 'getUserByIds' was in fact\n        // executed and that it executed only once\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        // assert the command is the one we're expecting\n        assertEquals(\"getUserByIds\", command.getCommandKey().name());\n        // confirm that it was a COLLAPSED command execution\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n        // and that it was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testReactive() throws Exception {\n\n        final Observable<User> u1 = userService.getUserByIdReactive(\"1\");\n        final Observable<User> u2 = userService.getUserByIdReactive(\"2\");\n        final Observable<User> u3 = userService.getUserByIdReactive(\"3\");\n        final Observable<User> u4 = userService.getUserByIdReactive(\"4\");\n        final Observable<User> u5 = userService.getUserByIdReactive(\"5\");\n\n        final Iterable<User> users = Observable.merge(u1, u2, u3, u4, u5).toBlocking().toIterable();\n\n        Set<String> expectedIds = Sets.newHashSet(\"1\", \"2\", \"3\", \"4\", \"5\");\n        for (User cUser : users) {\n            assertEquals(expectedIds.remove(cUser.getId()), true);\n        }\n        assertEquals(expectedIds.isEmpty(), true);\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        // assert the command is the one we're expecting\n        assertEquals(\"getUserByIds\", command.getCommandKey().name());\n        // confirm that it was a COLLAPSED command execution\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n        // and that it was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetUserByIdWithFallback() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserByIdWithFallback(\"1\");\n        Future<User> f2 = userService.getUserByIdWithFallback(\"2\");\n        Future<User> f3 = userService.getUserByIdWithFallback(\"3\");\n        Future<User> f4 = userService.getUserByIdWithFallback(\"4\");\n        Future<User> f5 = userService.getUserByIdWithFallback(\"5\");\n\n        assertEquals(\"name: 1\", f1.get().getName());\n        assertEquals(\"name: 2\", f2.get().getName());\n        assertEquals(\"name: 3\", f3.get().getName());\n        assertEquals(\"name: 4\", f4.get().getName());\n        assertEquals(\"name: 5\", f5.get().getName());\n        // two command should be executed: \"getUserByIdWithFallback\" and \"getUserByIdsWithFallback\"\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> getUserByIdsWithFallback = getHystrixCommandByKey(\"getUserByIdsWithFallback\");\n        com.netflix.hystrix.HystrixInvokableInfo getUserByIdsFallback = getHystrixCommandByKey(\"getUserByIdsFallback\");\n        // confirm that command has failed\n        assertTrue(getUserByIdsWithFallback.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserByIdsWithFallback.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        // and that fallback was successful\n        assertTrue(getUserByIdsFallback.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetUserByIdWithFallbackWithThrowableParam() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserByIdWithFallbackWithThrowableParam(\"1\");\n        Future<User> f2 = userService.getUserByIdWithFallbackWithThrowableParam(\"2\");\n        Future<User> f3 = userService.getUserByIdWithFallbackWithThrowableParam(\"3\");\n        Future<User> f4 = userService.getUserByIdWithFallbackWithThrowableParam(\"4\");\n        Future<User> f5 = userService.getUserByIdWithFallbackWithThrowableParam(\"5\");\n\n        assertEquals(\"name: 1\", f1.get().getName());\n        assertEquals(\"name: 2\", f2.get().getName());\n        assertEquals(\"name: 3\", f3.get().getName());\n        assertEquals(\"name: 4\", f4.get().getName());\n        assertEquals(\"name: 5\", f5.get().getName());\n        // 4 commands should be executed\n        assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> batchCommand = getHystrixCommandByKey(\"getUserByIdsThrowsException\");\n        com.netflix.hystrix.HystrixInvokableInfo fallback1 = getHystrixCommandByKey(\"getUserByIdsFallbackWithThrowableParam1\");\n        com.netflix.hystrix.HystrixInvokableInfo fallback2 = getHystrixCommandByKey(\"getUserByIdsFallbackWithThrowableParam2\");\n        com.netflix.hystrix.HystrixInvokableInfo fallback3 = getHystrixCommandByKey(\"getUserByIdsFallbackWithThrowableParam3\");\n        // confirm that command has failed\n        assertTrue(batchCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n\n        assertTrue(fallback1.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(fallback2.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(fallback2.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n\n        // and that last fallback3 was successful\n        assertTrue(fallback3.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testGetUserByIdWrongBatchMethodArgType() {\n        userService.getUserByIdWrongBatchMethodArgType(\"1\");\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testGetUserByIdWrongBatchMethodReturnType() {\n        userService.getUserByIdWrongBatchMethodArgType(\"1\");\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testGetUserByIdWrongCollapserMethodReturnType() {\n        userService.getUserByIdWrongCollapserMethodReturnType(\"1\");\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testGetUserByIdWrongCollapserMultipleArgs() {\n        userService.getUserByIdWrongCollapserMultipleArgs(\"1\", \"2\");\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testGetUserByIdWrongCollapserNoArgs() {\n        userService.getUserByIdWrongCollapserNoArgs();\n    }\n\n    public static class UserService {\n\n        public static final Logger log = LoggerFactory.getLogger(UserService.class);\n        public static final User DEFAULT_USER = new User(\"def\", \"def\");\n\n\n        @HystrixCollapser(batchMethod = \"getUserByIds\",\n                collapserProperties = {@HystrixProperty(name = \"timerDelayInMilliseconds\", value = \"200\")})\n        public Future<User> getUserById(String id) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIdsWithFallback\",\n                collapserProperties = {@HystrixProperty(name = \"timerDelayInMilliseconds\", value = \"200\")})\n        public Future<User> getUserByIdWithFallback(String id) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIds\",\n                collapserProperties = {@HystrixProperty(name = \"timerDelayInMilliseconds\", value = \"200\")})\n        public Observable<User> getUserByIdReactive(String id) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIdsThrowsException\",\n                collapserProperties = {@HystrixProperty(name = \"timerDelayInMilliseconds\", value = \"200\")})\n        public Future<User> getUserByIdWithFallbackWithThrowableParam(String id) {\n            return null;\n        }\n\n        @HystrixCommand(\n                fallbackMethod = \"getUserByIdsFallbackWithThrowableParam1\",\n                commandProperties = {\n                @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"10000\")// for debug\n        })\n        public List<User> getUserByIdsThrowsException(List<String> ids) {\n            throw new RuntimeException(\"getUserByIdsFails failed\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"getUserByIdsFallbackWithThrowableParam2\")\n        private List<User> getUserByIdsFallbackWithThrowableParam1(List<String> ids, Throwable e) {\n            if (e.getMessage().equals(\"getUserByIdsFails failed\")) {\n                throw new RuntimeException(\"getUserByIdsFallbackWithThrowableParam1 failed\");\n            }\n            List<User> users = new ArrayList<User>();\n            for (String id : ids) {\n                users.add(new User(id, \"name: \" + id));\n            }\n            return users;\n        }\n\n        @HystrixCommand(fallbackMethod = \"getUserByIdsFallbackWithThrowableParam3\")\n        private List<User> getUserByIdsFallbackWithThrowableParam2(List<String> ids) {\n            throw new RuntimeException(\"getUserByIdsFallbackWithThrowableParam2 failed\");\n        }\n\n        @HystrixCommand\n        private List<User> getUserByIdsFallbackWithThrowableParam3(List<String> ids, Throwable e) {\n            if (!e.getMessage().equals(\"getUserByIdsFallbackWithThrowableParam2 failed\")) {\n                throw new RuntimeException(\"getUserByIdsFallbackWithThrowableParam3 failed\");\n            }\n            List<User> users = new ArrayList<User>();\n            for (String id : ids) {\n                users.add(new User(id, \"name: \" + id));\n            }\n            return users;\n        }\n\n        @HystrixCommand(commandProperties = {\n                @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"10000\")// for debug\n        })\n        public List<User> getUserByIds(List<String> ids) {\n            List<User> users = new ArrayList<User>();\n            for (String id : ids) {\n                users.add(new User(id, \"name: \" + id));\n            }\n            log.debug(\"executing on thread id: {}\", Thread.currentThread().getId());\n            return users;\n        }\n\n        @HystrixCommand(fallbackMethod = \"getUserByIdsFallback\",\n                commandProperties = {\n                        @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"10000\")// for debug\n                })\n        public List<User> getUserByIdsWithFallback(List<String> ids) {\n            throw new RuntimeException(\"not found\");\n        }\n\n\n        @HystrixCommand\n        private List<User> getUserByIdsFallback(List<String> ids) {\n            List<User> users = new ArrayList<User>();\n            for (String id : ids) {\n                users.add(new User(id, \"name: \" + id));\n            }\n            return users;\n        }\n\n        // wrong return type, expected: Future<User> or User, because batch command getUserByIds returns List<User>\n        @HystrixCollapser(batchMethod = \"getUserByIds\")\n        public Long getUserByIdWrongCollapserMethodReturnType(String id) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIds\")\n        public Future<User> getUserByIdWrongCollapserMultipleArgs(String id, String name) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIds\")\n        public Future<User> getUserByIdWrongCollapserNoArgs() {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIdsWrongBatchMethodArgType\")\n        public Future<User> getUserByIdWrongBatchMethodArgType(String id) {\n            return null;\n        }\n\n        // wrong arg type, expected: List<String>\n        @HystrixCommand\n        public List<User> getUserByIdsWrongBatchMethodArgType(List<Integer> ids) {\n            return null;\n        }\n\n        @HystrixCollapser(batchMethod = \"getUserByIdsWrongBatchMethodReturnType\")\n        public Future<User> getUserByIdWrongBatchMethodReturnType(String id) {\n            return null;\n        }\n\n        // wrong return type, expected: List<User>\n        @HystrixCommand\n        public List<Integer> getUserByIdsWrongBatchMethodReturnType(List<String> ids) {\n            return null;\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/command/BasicCommandTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.command;\n\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.command.AsyncResult;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\npublic abstract class BasicCommandTest extends BasicHystrixTest {\n\n    private UserService userService;\n    private AdvancedUserService advancedUserService;\n    private GenericService<String, Long, User> genericUserService;\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n        advancedUserService = createAdvancedUserServiceService();\n        genericUserService = createGenericUserService();\n    }\n\n    @Test\n    public void testGetUserAsync() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserAsync(\"1\", \"name: \");\n\n        assertEquals(\"name: 1\", f1.get().getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo<?> command = getCommand();\n        // assert the command key name is the we're expecting\n        assertEquals(\"GetUserCommand\", command.getCommandKey().name());\n        // assert the command group key name is the we're expecting\n        assertEquals(\"UserService\", command.getCommandGroup().name());\n        // assert the command thread pool key name is the we're expecting\n        assertEquals(\"CommandTestAsync\", command.getThreadPoolKey().name());\n        // it was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetUserSync() {\n        User u1 = userService.getUserSync(\"1\", \"name: \");\n        assertGetUserSnycCommandExecuted(u1);\n    }\n\n    @Test\n    public void shouldWorkWithInheritedMethod() {\n        User u1 = advancedUserService.getUserSync(\"1\", \"name: \");\n        assertGetUserSnycCommandExecuted(u1);\n    }\n\n    @Test\n    public void should_work_with_parameterized_method() throws Exception {\n        assertEquals(Integer.valueOf(1), userService.echo(1));\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        assertTrue(getCommand().getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void should_work_with_parameterized_asyncMethod() throws Exception {\n        assertEquals(Integer.valueOf(1), userService.echoAsync(1).get());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        assertTrue(getCommand().getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void should_work_with_genericClass_fallback() {\n        User user = genericUserService.getByKeyForceFail(\"1\", 2L);\n        assertEquals(\"name: 2\", user.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n\n        assertEquals(\"getByKeyForceFail\", command.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that fallback was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n\n    private void assertGetUserSnycCommandExecuted(User u1) {\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo<?> command = getCommand();\n        assertEquals(\"getUserSync\", command.getCommandKey().name());\n        assertEquals(\"UserGroup\", command.getCommandGroup().name());\n        assertEquals(\"UserGroup\", command.getThreadPoolKey().name());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    private com.netflix.hystrix.HystrixInvokableInfo<?> getCommand() {\n        return HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n    }\n\n    protected abstract UserService createUserService();\n    protected abstract AdvancedUserService createAdvancedUserServiceService();\n    protected abstract GenericService<String, Long, User> createGenericUserService();\n\n    public interface GenericService<K1, K2, V> {\n        V getByKey(K1 key1, K2 key2);\n        V getByKeyForceFail(K1 key, K2 key2);\n        V fallback(K1 key, K2 key2);\n    }\n\n    public static class GenericUserService implements GenericService<String, Long, User> {\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        @Override\n        public User getByKey(String sKey, Long lKey) {\n            return new User(sKey, \"name: \" + lKey); // it should be network call\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        @Override\n        public User getByKeyForceFail(String sKey, Long lKey) {\n            throw new RuntimeException(\"force fail\");\n        }\n\n        @Override\n        public User fallback(String sKey, Long lKey) {\n            return new User(sKey, \"name: \" + lKey);\n        }\n\n    }\n\n    public static class UserService {\n\n        @HystrixCommand(commandKey = \"GetUserCommand\", threadPoolKey = \"CommandTestAsync\")\n        public Future<User> getUserAsync(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(id, name + id); // it should be network call\n                }\n            };\n        }\n\n        @HystrixCommand(groupKey = \"UserGroup\")\n        public User getUserSync(String id, String name) {\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand\n        public <T> T echo(T value) {\n            return value;\n        }\n\n        @HystrixCommand\n        public <T> Future<T> echoAsync(final T value) {\n            return new AsyncResult<T>() {\n                @Override\n                public T invoke() {\n                    return value;\n                }\n            };\n        }\n\n    }\n\n    public static class AdvancedUserService extends UserService {\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/configuration/collapser/BasicCollapserPropertiesTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.configuration.collapser;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.MAX_REQUESTS_IN_BATCH;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.TIMER_DELAY_IN_MILLISECONDS;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicCollapserPropertiesTest extends BasicHystrixTest {\n\n    private UserService userService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n    }\n\n    @Test\n    public void testCollapser() throws ExecutionException, InterruptedException {\n\n        User u1 = userService.getUser(\"1\");\n        User u2 = userService.getUser(\"2\");\n        User u3 = userService.getUser(\"3\");\n        User u4 = userService.getUser(\"4\");\n\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(\"name: 2\", u2.getName());\n        assertEquals(\"name: 3\", u3.getName());\n        assertEquals(\"name: 4\", u4.getName());\n        assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"getUsers\", command.getCommandKey().name());\n        // confirm that it was a COLLAPSED command execution\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n        // and that it was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    public static class UserService {\n\n        @HystrixCollapser(\n                batchMethod = \"getUsers\",\n                collapserKey = \"GetUserCollapser\", collapserProperties = {\n                @HystrixProperty(name = TIMER_DELAY_IN_MILLISECONDS, value = \"200\"),\n                @HystrixProperty(name = MAX_REQUESTS_IN_BATCH, value = \"1\"),\n        })\n        public User getUser(String id) {\n            return null;\n        }\n\n        @HystrixCommand\n        public List<User> getUsers(List<String> ids) {\n            List<User> users = new ArrayList<User>();\n            for (String id : ids) {\n                users.add(new User(id, \"name: \" + id));\n            }\n            return users;\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/configuration/command/BasicCommandDefaultPropertiesTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.configuration.command;\n\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS;\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Created by dmgcodevil.\n */\npublic abstract class BasicCommandDefaultPropertiesTest extends BasicHystrixTest {\n\n    private Service service;\n\n    protected abstract Service createService();\n\n    @Before\n    public void setUp() throws Exception {\n        service = createService();\n    }\n\n    @Test\n    public void testCommandInheritsDefaultGroupKey() {\n        service.commandInheritsDefaultProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"DefaultGroupKey\", command.getCommandGroup().name());\n    }\n\n    @Test\n    public void testCommandOverridesDefaultGroupKey() {\n        service.commandOverridesGroupKey();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"SpecificGroupKey\", command.getCommandGroup().name());\n    }\n\n    @Test\n    public void testCommandInheritsDefaultThreadPoolKey() {\n        service.commandInheritsDefaultProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"DefaultThreadPoolKey\", command.getThreadPoolKey().name());\n    }\n\n    @Test\n    public void testCommandOverridesDefaultThreadPoolKey() {\n        service.commandOverridesThreadPoolKey();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"SpecificThreadPoolKey\", command.getThreadPoolKey().name());\n    }\n\n    @Test\n    public void testCommandInheritsDefaultCommandProperties() {\n        service.commandInheritsDefaultProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(456, command.getProperties().executionTimeoutInMilliseconds().get().intValue());\n    }\n\n    @Test\n    public void testCommandOverridesDefaultCommandProperties() {\n        service.commandOverridesDefaultCommandProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(654, command.getProperties().executionTimeoutInMilliseconds().get().intValue());\n    }\n\n    @Test\n    public void testCommandInheritsThreadPollProperties() {\n        service.commandInheritsDefaultProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(command);\n\n        assertEquals(123, properties.maxQueueSize().get().intValue());\n    }\n\n    @Test\n    public void testCommandOverridesDefaultThreadPollProperties() {\n        service.commandOverridesDefaultThreadPoolProperties();\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(command);\n\n        assertEquals(321, properties.maxQueueSize().get().intValue());\n    }\n\n    @DefaultProperties(groupKey = \"DefaultGroupKey\", threadPoolKey = \"DefaultThreadPoolKey\",\n            commandProperties = {\n                    @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"456\")\n            },\n            threadPoolProperties = {\n                    @HystrixProperty(name = \"maxQueueSize\", value = \"123\")\n            }\n    )\n    public static class Service {\n\n        @HystrixCommand\n        public Object commandInheritsDefaultProperties() {\n            return null;\n        }\n\n        @HystrixCommand(groupKey = \"SpecificGroupKey\")\n        public Object commandOverridesGroupKey() {\n            return null;\n        }\n\n        @HystrixCommand(threadPoolKey = \"SpecificThreadPoolKey\")\n        public Object commandOverridesThreadPoolKey() {\n            return null;\n        }\n\n        @HystrixCommand(commandProperties = {\n                @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"654\")\n        })\n        public Object commandOverridesDefaultCommandProperties() {\n            return null;\n        }\n\n        @HystrixCommand(threadPoolProperties = {\n                @HystrixProperty(name = \"maxQueueSize\", value = \"321\")\n        })\n        public Object commandOverridesDefaultThreadPoolProperties() {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/configuration/command/BasicCommandPropertiesTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.configuration.command;\n\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_CLOSED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_FORCE_OPEN;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.FALLBACK_ENABLED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_BUCKET_SIZE;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_ENABLED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_NUM_BUCKETS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.METRICS_ROLLING_STATS_NUM_BUCKETS;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.REQUEST_CACHE_ENABLED;\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.REQUEST_LOG_ENABLED;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicCommandPropertiesTest extends BasicHystrixTest {\n\n    private UserService userService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n    }\n\n    @Test\n    public void testGetUser() throws NoSuchFieldException, IllegalAccessException {\n        User u1 = userService.getUser(\"1\", \"name: \");\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"GetUserCommand\", command.getCommandKey().name());\n        assertEquals(\"UserGroupKey\", command.getCommandGroup().name());\n        assertEquals(\"Test\", command.getThreadPoolKey().name());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        // assert properties\n        assertEquals(110, command.getProperties().executionTimeoutInMilliseconds().get().intValue());\n        assertEquals(false, command.getProperties().executionIsolationThreadInterruptOnTimeout().get());\n\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(command);\n\n        assertEquals(30, (int) properties.coreSize().get());\n        assertEquals(35, (int) properties.maximumSize().get());\n        assertEquals(true, properties.getAllowMaximumSizeToDivergeFromCoreSize().get());\n        assertEquals(101, (int) properties.maxQueueSize().get());\n        assertEquals(2, (int) properties.keepAliveTimeMinutes().get());\n        assertEquals(15, (int) properties.queueSizeRejectionThreshold().get());\n        assertEquals(1440, (int) properties.metricsRollingStatisticalWindowInMilliseconds().get());\n        assertEquals(12, (int) properties.metricsRollingStatisticalWindowBuckets().get());\n    }\n\n    @Test\n    public void testGetUserDefaultPropertiesValues() {\n        User u1 = userService.getUserDefProperties(\"1\", \"name: \");\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"getUserDefProperties\", command.getCommandKey().name());\n        assertEquals(\"UserService\", command.getCommandGroup().name());\n        assertEquals(\"UserService\", command.getThreadPoolKey().name());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetUserDefGroupKeyWithSpecificThreadPoolKey() {\n        User u1 = userService.getUserDefGroupKeyWithSpecificThreadPoolKey(\"1\", \"name: \");\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"getUserDefGroupKeyWithSpecificThreadPoolKey\", command.getCommandKey().name());\n        assertEquals(\"UserService\", command.getCommandGroup().name());\n        assertEquals(\"CustomThreadPool\", command.getThreadPoolKey().name());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testHystrixCommandProperties() {\n        User u1 = userService.getUsingAllCommandProperties(\"1\", \"name: \");\n        assertEquals(\"name: 1\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        // assert properties\n        assertEquals(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE, command.getProperties().executionIsolationStrategy().get());\n        assertEquals(500, command.getProperties().executionTimeoutInMilliseconds().get().intValue());\n        assertEquals(true, command.getProperties().executionTimeoutEnabled().get().booleanValue());\n        assertEquals(false, command.getProperties().executionIsolationThreadInterruptOnTimeout().get().booleanValue());\n        assertEquals(10, command.getProperties().executionIsolationSemaphoreMaxConcurrentRequests().get().intValue());\n        assertEquals(15, command.getProperties().fallbackIsolationSemaphoreMaxConcurrentRequests().get().intValue());\n        assertEquals(false, command.getProperties().fallbackEnabled().get().booleanValue());\n        assertEquals(false, command.getProperties().circuitBreakerEnabled().get().booleanValue());\n        assertEquals(30, command.getProperties().circuitBreakerRequestVolumeThreshold().get().intValue());\n        assertEquals(250, command.getProperties().circuitBreakerSleepWindowInMilliseconds().get().intValue());\n        assertEquals(60, command.getProperties().circuitBreakerErrorThresholdPercentage().get().intValue());\n        assertEquals(false, command.getProperties().circuitBreakerForceOpen().get().booleanValue());\n        assertEquals(true, command.getProperties().circuitBreakerForceClosed().get().booleanValue());\n        assertEquals(false, command.getProperties().metricsRollingPercentileEnabled().get().booleanValue());\n        assertEquals(400, command.getProperties().metricsRollingPercentileWindowInMilliseconds().get().intValue());\n        assertEquals(5, command.getProperties().metricsRollingPercentileWindowBuckets().get().intValue());\n        assertEquals(6, command.getProperties().metricsRollingPercentileBucketSize().get().intValue());\n        assertEquals(10, command.getProperties().metricsRollingStatisticalWindowBuckets().get().intValue());\n        assertEquals(500, command.getProperties().metricsRollingStatisticalWindowInMilliseconds().get().intValue());\n        assertEquals(312, command.getProperties().metricsHealthSnapshotIntervalInMilliseconds().get().intValue());\n        assertEquals(false, command.getProperties().requestCacheEnabled().get().booleanValue());\n        assertEquals(true, command.getProperties().requestLogEnabled().get().booleanValue());\n    }\n\n    public static class UserService {\n\n        @HystrixCommand(commandKey = \"GetUserCommand\", groupKey = \"UserGroupKey\", threadPoolKey = \"Test\",\n                commandProperties = {\n                        @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"110\"),\n                        @HystrixProperty(name = \"execution.isolation.thread.interruptOnTimeout\", value = \"false\")\n                },\n                threadPoolProperties = {\n                        @HystrixProperty(name = \"coreSize\", value = \"30\"),\n                        @HystrixProperty(name = \"maximumSize\", value = \"35\"),\n                        @HystrixProperty(name = \"allowMaximumSizeToDivergeFromCoreSize\", value = \"true\"),\n                        @HystrixProperty(name = \"maxQueueSize\", value = \"101\"),\n                        @HystrixProperty(name = \"keepAliveTimeMinutes\", value = \"2\"),\n                        @HystrixProperty(name = \"metrics.rollingStats.numBuckets\", value = \"12\"),\n                        @HystrixProperty(name = \"queueSizeRejectionThreshold\", value = \"15\"),\n                        @HystrixProperty(name = \"metrics.rollingStats.timeInMilliseconds\", value = \"1440\")\n                })\n        public User getUser(String id, String name) {\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand\n        public User getUserDefProperties(String id, String name) {\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand(threadPoolKey = \"CustomThreadPool\")\n        public User getUserDefGroupKeyWithSpecificThreadPoolKey(String id, String name) {\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand(\n                commandProperties = {\n                        @HystrixProperty(name = EXECUTION_ISOLATION_STRATEGY, value = \"SEMAPHORE\"),\n                        @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"500\"),\n                        @HystrixProperty(name = EXECUTION_TIMEOUT_ENABLED, value = \"true\"),\n                        @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, value = \"false\"),\n                        @HystrixProperty(name = EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = \"10\"),\n                        @HystrixProperty(name = FALLBACK_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = \"15\"),\n                        @HystrixProperty(name = FALLBACK_ENABLED, value = \"false\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_ENABLED, value = \"false\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value = \"30\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = \"250\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = \"60\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_FORCE_OPEN, value = \"false\"),\n                        @HystrixProperty(name = CIRCUIT_BREAKER_FORCE_CLOSED, value = \"true\"),\n                        @HystrixProperty(name = METRICS_ROLLING_PERCENTILE_ENABLED, value = \"false\"),\n                        @HystrixProperty(name = METRICS_ROLLING_PERCENTILE_TIME_IN_MILLISECONDS, value = \"400\"),\n                        @HystrixProperty(name = METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value = \"500\"),\n                        @HystrixProperty(name = METRICS_ROLLING_STATS_NUM_BUCKETS, value = \"10\"),\n                        @HystrixProperty(name = METRICS_ROLLING_PERCENTILE_NUM_BUCKETS, value = \"5\"),\n                        @HystrixProperty(name = METRICS_ROLLING_PERCENTILE_BUCKET_SIZE, value = \"6\"),\n                        @HystrixProperty(name = METRICS_HEALTH_SNAPSHOT_INTERVAL_IN_MILLISECONDS, value = \"312\"),\n                        @HystrixProperty(name = REQUEST_CACHE_ENABLED, value = \"false\"),\n                        @HystrixProperty(name = REQUEST_LOG_ENABLED, value = \"true\")\n                }\n        )\n        public User getUsingAllCommandProperties(String id, String name) {\n            return new User(id, name + id); // it should be network call\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/configuration/fallback/BasicFallbackDefaultPropertiesTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.configuration.fallback;\n\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS;\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertEquals;\n\n\npublic abstract class BasicFallbackDefaultPropertiesTest extends BasicHystrixTest {\n\n    private Service service;\n\n    protected abstract Service createService();\n\n    @Before\n    public void setUp() throws Exception {\n        service = createService();\n    }\n\n    @Test\n    public void testFallbackInheritsDefaultGroupKey() {\n        service.commandWithFallbackInheritsDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackInheritsDefaultProperties\");\n        assertEquals(\"DefaultGroupKey\", fallbackCommand.getCommandGroup().name());\n    }\n\n    @Test\n    public void testFallbackInheritsDefaultThreadPoolKey() {\n        service.commandWithFallbackInheritsDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackInheritsDefaultProperties\");\n        assertEquals(\"DefaultThreadPoolKey\", fallbackCommand.getThreadPoolKey().name());\n    }\n\n    @Test\n    public void testFallbackInheritsDefaultCommandProperties() {\n        service.commandWithFallbackInheritsDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackInheritsDefaultProperties\");\n        assertEquals(456, fallbackCommand.getProperties().executionTimeoutInMilliseconds().get().intValue());\n    }\n\n    @Test\n    public void testFallbackInheritsThreadPollProperties() {\n        service.commandWithFallbackInheritsDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackInheritsDefaultProperties\");\n\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(fallbackCommand);\n\n        assertEquals(123, properties.maxQueueSize().get().intValue());\n    }\n\n    @Test\n    public void testFallbackOverridesDefaultGroupKey() {\n        service.commandWithFallbackOverridesDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackOverridesDefaultProperties\");\n        assertEquals(\"FallbackGroupKey\", fallbackCommand.getCommandGroup().name());\n    }\n\n    @Test\n    public void testFallbackOverridesDefaultThreadPoolKey() {\n        service.commandWithFallbackOverridesDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackOverridesDefaultProperties\");\n        assertEquals(\"FallbackThreadPoolKey\", fallbackCommand.getThreadPoolKey().name());\n    }\n\n    @Test\n    public void testFallbackOverridesDefaultCommandProperties() {\n        service.commandWithFallbackOverridesDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackOverridesDefaultProperties\");\n        assertEquals(654, fallbackCommand.getProperties().executionTimeoutInMilliseconds().get().intValue());\n    }\n\n    @Test\n    public void testFallbackOverridesThreadPollProperties() {\n        service.commandWithFallbackOverridesDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackOverridesDefaultProperties\");\n\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(fallbackCommand);\n\n        assertEquals(321, properties.maxQueueSize().get().intValue());\n    }\n\n    @Test\n    public void testCommandOverridesDefaultPropertiesWithFallbackInheritsDefaultProperties(){\n        service.commandOverridesDefaultPropertiesWithFallbackInheritsDefaultProperties();\n        com.netflix.hystrix.HystrixInvokableInfo fallbackCommand = getHystrixCommandByKey(\"fallbackInheritsDefaultProperties\");\n        HystrixThreadPoolProperties properties = getThreadPoolProperties(fallbackCommand);\n        assertEquals(\"DefaultGroupKey\", fallbackCommand.getCommandGroup().name());\n        assertEquals(\"DefaultThreadPoolKey\", fallbackCommand.getThreadPoolKey().name());\n        assertEquals(456, fallbackCommand.getProperties().executionTimeoutInMilliseconds().get().intValue());\n        assertEquals(123, properties.maxQueueSize().get().intValue());\n    }\n\n    @DefaultProperties(groupKey = \"DefaultGroupKey\",\n            threadPoolKey = \"DefaultThreadPoolKey\",\n            commandProperties = {\n                    @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"456\")\n            },\n            threadPoolProperties = {\n                    @HystrixProperty(name = \"maxQueueSize\", value = \"123\")\n            })\n    public static class Service {\n\n        @HystrixCommand(fallbackMethod = \"fallbackInheritsDefaultProperties\")\n        public Object commandWithFallbackInheritsDefaultProperties() {\n            throw new RuntimeException();\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackOverridesDefaultProperties\")\n        public Object commandWithFallbackOverridesDefaultProperties() {\n            throw new RuntimeException();\n        }\n\n        @HystrixCommand(groupKey = \"CommandGroupKey\",\n                threadPoolKey = \"CommandThreadPoolKey\",\n                commandProperties = {\n                        @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"654\")\n                },\n                threadPoolProperties = {\n                        @HystrixProperty(name = \"maxQueueSize\", value = \"321\")\n                }, fallbackMethod = \"fallbackInheritsDefaultProperties\")\n        public Object commandOverridesDefaultPropertiesWithFallbackInheritsDefaultProperties() {\n            throw new RuntimeException();\n        }\n\n        @HystrixCommand\n        private Object fallbackInheritsDefaultProperties() {\n            return null;\n        }\n\n        @HystrixCommand(groupKey = \"FallbackGroupKey\",\n                threadPoolKey = \"FallbackThreadPoolKey\",\n                commandProperties = {\n                        @HystrixProperty(name = EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = \"654\")\n                },\n                threadPoolProperties = {\n                        @HystrixProperty(name = \"maxQueueSize\", value = \"321\")\n                })\n        private Object fallbackOverridesDefaultProperties() {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/domain/Domain.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.domain;\n\n\npublic class Domain {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/domain/Profile.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.domain;\n\n/**\n * Created by dmgcodevil on 1/9/2015.\n */\npublic class Profile {\n    private String email;\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/domain/User.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.domain;\n\n/**\n * Simple domain object for tests.\n */\npublic class User extends Domain{\n\n    private String id;\n    private String name;\n    private Profile profile;\n\n\n    public User() {\n    }\n\n    public User(String id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Profile getProfile() {\n        return profile;\n    }\n\n    public void setProfile(Profile profile) {\n        this.profile = profile;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"User{\");\n        sb.append(\"id='\").append(id).append('\\'');\n        sb.append(\", name='\").append(name).append('\\'');\n        sb.append('}');\n        return sb.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if(this == o) {\n            return true;\n        }\n        if(!(o instanceof User)) {\n            return false;\n        }\n\n        User user = (User) o;\n\n        if(id != null ? !id.equals(user.id) : user.id != null) {\n            return false;\n        }\n        if(name != null ? !name.equals(user.name) : user.name != null) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = id != null ? id.hashCode() : 0;\n        result = 31 * result + (name != null ? name.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/error/BasicDefaultIgnoreExceptionsTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.error;\n\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\n/**\n * Test for {@link DefaultProperties#ignoreExceptions()} feature.\n *\n * <p>\n * Created by dmgcodevil.\n */\npublic abstract class BasicDefaultIgnoreExceptionsTest {\n    private Service service;\n\n    @Before\n    public void setUp() throws Exception {\n        service = createService();\n    }\n\n    protected abstract Service createService();\n\n    @Test(expected = BadRequestException.class)\n    public void testDefaultIgnoreException() {\n        service.commandInheritsDefaultIgnoreExceptions();\n    }\n\n    @Test(expected = SpecificException.class)\n    public void testCommandOverridesDefaultIgnoreExceptions() {\n        service.commandOverridesDefaultIgnoreExceptions(SpecificException.class);\n    }\n\n    @Test(expected = BadRequestException.class)\n    public void testCommandOverridesDefaultIgnoreExceptions_nonIgnoreExceptionShouldBePropagated() {\n        // method throws BadRequestException that isn't ignored\n        service.commandOverridesDefaultIgnoreExceptions(BadRequestException.class);\n    }\n\n    @Ignore // https://github.com/Netflix/Hystrix/issues/993#issuecomment-229542203\n    @Test(expected = BadRequestException.class)\n    public void testFallbackCommandInheritsDefaultIgnoreException() {\n        service.commandWithFallbackInheritsDefaultIgnoreExceptions();\n    }\n\n    @Ignore // https://github.com/Netflix/Hystrix/issues/993#issuecomment-229542203\n    @Test(expected = SpecificException.class)\n    public void testFallbackCommandOverridesDefaultIgnoreExceptions() {\n        service.commandWithFallbackOverridesDefaultIgnoreExceptions(SpecificException.class);\n    }\n\n    @Test(expected = BadRequestException.class)\n    public void testFallbackCommandOverridesDefaultIgnoreExceptions_nonIgnoreExceptionShouldBePropagated() {\n        service.commandWithFallbackOverridesDefaultIgnoreExceptions(BadRequestException.class);\n    }\n\n    @DefaultProperties(ignoreExceptions = BadRequestException.class)\n    public static class Service {\n        @HystrixCommand\n        public Object commandInheritsDefaultIgnoreExceptions() throws BadRequestException {\n            // this exception will be ignored (wrapped in HystrixBadRequestException) because specified in default ignore exceptions\n            throw new BadRequestException(\"from 'commandInheritsIgnoreExceptionsFromDefault'\");\n        }\n\n        @HystrixCommand(ignoreExceptions = SpecificException.class)\n        public Object commandOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) throws BadRequestException, SpecificException  {\n            if(errorType.equals(BadRequestException.class)){\n                // isn't ignored because command doesn't specify this exception type in 'ignoreExceptions'\n                throw new BadRequestException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n            }\n            // something went wrong, this error is ignored because specified in the command's ignoreExceptions\n            throw new SpecificException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackInheritsDefaultIgnoreExceptions\")\n        public Object commandWithFallbackInheritsDefaultIgnoreExceptions() throws SpecificException {\n            // isn't ignored, need to trigger fallback\n            throw new SpecificException(\"from 'commandWithFallbackInheritsDefaultIgnoreExceptions'\");\n        }\n\n        @HystrixCommand\n        private Object fallbackInheritsDefaultIgnoreExceptions() throws BadRequestException {\n            // should be ignored because specified in global ignore exception, fallback command inherits default ignore exceptions\n            throw new BadRequestException(\"from 'fallbackInheritsDefaultIgnoreExceptions'\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackOverridesDefaultIgnoreExceptions\")\n        public Object commandWithFallbackOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) {\n            // isn't ignored, need to trigger fallback\n            throw new SpecificException();\n        }\n\n        @HystrixCommand(ignoreExceptions = SpecificException.class)\n        private Object fallbackOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) {\n            if(errorType.equals(BadRequestException.class)){\n                // isn't ignored because fallback doesn't specify this exception type in 'ignoreExceptions'\n                throw new BadRequestException(\"from 'fallbackOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n            }\n            // something went wrong, this error is ignored because specified in the fallback's ignoreExceptions\n            throw new SpecificException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n        }\n    }\n\n    public static final class BadRequestException extends RuntimeException {\n        public BadRequestException() {\n        }\n\n        public BadRequestException(String message) {\n            super(message);\n        }\n    }\n\n    public static final class SpecificException extends RuntimeException {\n        public SpecificException() {\n        }\n\n        public SpecificException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/error/BasicDefaultRaiseHystrixExceptionsTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.error;\n\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.Hystrix;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\nimport rx.Observable;\nimport rx.observers.TestSubscriber;\n\n/**\n * Created by Mike Cowan\n */\npublic abstract class BasicDefaultRaiseHystrixExceptionsTest {\n\n    private Service service;\n\n    @Before\n    public void setUp() throws Exception {\n        service = createService();\n    }\n\n    protected abstract Service createService();\n\n    @Test(expected = BadRequestException.class)\n    public void testDefaultIgnoreException() {\n        service.commandInheritsDefaultIgnoreExceptions();\n    }\n\n    @Test(expected = SpecificException.class)\n    public void testCommandOverridesDefaultIgnoreExceptions() {\n        service.commandOverridesDefaultIgnoreExceptions(SpecificException.class);\n    }\n\n    @Test(expected = HystrixRuntimeException.class)\n    public void testCommandOverridesDefaultIgnoreExceptions_nonIgnoreExceptionShouldBePropagated() {\n        // method throws BadRequestException that isn't ignored\n        service.commandOverridesDefaultIgnoreExceptions(BadRequestException.class);\n    }\n\n    @Ignore // https://github.com/Netflix/Hystrix/issues/993#issuecomment-229542203\n    @Test(expected = BadRequestException.class)\n    public void testFallbackCommandInheritsDefaultIgnoreException() {\n        service.commandWithFallbackInheritsDefaultIgnoreExceptions();\n    }\n\n    @Ignore // https://github.com/Netflix/Hystrix/issues/993#issuecomment-229542203\n    @Test(expected = SpecificException.class)\n    public void testFallbackCommandOverridesDefaultIgnoreExceptions() {\n        service.commandWithFallbackOverridesDefaultIgnoreExceptions(SpecificException.class);\n    }\n\n    @Test(expected = HystrixRuntimeException.class)\n    public void testFallbackCommandOverridesDefaultIgnoreExceptions_nonIgnoreExceptionShouldBePropagated() {\n        service.commandWithFallbackOverridesDefaultIgnoreExceptions(BadRequestException.class);\n    }\n\n    @Test(expected = HystrixRuntimeException.class)\n    public void testRaiseHystrixRuntimeException() {\n        service.commandShouldRaiseHystrixRuntimeException();\n    }\n\n    @Test\n    public void testObservableRaiseHystrixRuntimeException() {\n        TestSubscriber<Void> testSubscriber = new TestSubscriber<Void>();\n        service.observableCommandShouldRaiseHystrixRuntimeException().subscribe(testSubscriber);\n        testSubscriber.assertError(HystrixRuntimeException.class);\n    }\n\n    @DefaultProperties(ignoreExceptions = BadRequestException.class, raiseHystrixExceptions = {HystrixException.RUNTIME_EXCEPTION})\n    public static class Service {\n        @HystrixCommand\n        public Object commandShouldRaiseHystrixRuntimeException() throws SpecificException {\n            throw new SpecificException(\"from 'commandShouldRaiseHystrixRuntimeException'\");\n        }\n\n        @HystrixCommand\n        public Observable<Void> observableCommandShouldRaiseHystrixRuntimeException() throws SpecificException {\n            return Observable.error(new SpecificException(\"from 'observableCommandShouldRaiseHystrixRuntimeException'\"));\n        }\n\n        @HystrixCommand\n         public Object commandInheritsDefaultIgnoreExceptions() throws BadRequestException {\n            // this exception will be ignored (wrapped in HystrixBadRequestException) because specified in default ignore exceptions\n            throw new BadRequestException(\"from 'commandInheritsIgnoreExceptionsFromDefault'\");\n        }\n\n        @HystrixCommand(ignoreExceptions = SpecificException.class)\n        public Object commandOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) throws BadRequestException, SpecificException  {\n            if(errorType.equals(BadRequestException.class)){\n                // isn't ignored because command doesn't specify this exception type in 'ignoreExceptions'\n                throw new BadRequestException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n            }\n            // something went wrong, this error is ignored because specified in the command's ignoreExceptions\n            throw new SpecificException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackInheritsDefaultIgnoreExceptions\")\n        public Object commandWithFallbackInheritsDefaultIgnoreExceptions() throws SpecificException {\n            // isn't ignored, need to trigger fallback\n            throw new SpecificException(\"from 'commandWithFallbackInheritsDefaultIgnoreExceptions'\");\n        }\n\n        @HystrixCommand\n        private Object fallbackInheritsDefaultIgnoreExceptions() throws BadRequestException {\n            // should be ignored because specified in global ignore exception, fallback command inherits default ignore exceptions\n            throw new BadRequestException(\"from 'fallbackInheritsDefaultIgnoreExceptions'\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackOverridesDefaultIgnoreExceptions\")\n        public Object commandWithFallbackOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) {\n            // isn't ignored, need to trigger fallback\n            throw new SpecificException();\n        }\n\n        @HystrixCommand(ignoreExceptions = SpecificException.class)\n        private Object fallbackOverridesDefaultIgnoreExceptions(Class<? extends Throwable> errorType) {\n            if(errorType.equals(BadRequestException.class)){\n                // isn't ignored because fallback doesn't specify this exception type in 'ignoreExceptions'\n                throw new BadRequestException(\"from 'fallbackOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n            }\n            // something went wrong, this error is ignored because specified in the fallback's ignoreExceptions\n            throw new SpecificException(\"from 'commandOverridesDefaultIgnoreExceptions', cause: \" + errorType.getSimpleName());\n        }\n    }\n\n    public static final class BadRequestException extends RuntimeException {\n        public BadRequestException() {\n        }\n\n        public BadRequestException(String message) {\n            super(message);\n        }\n    }\n\n    public static final class SpecificException extends RuntimeException {\n        public SpecificException() {\n        }\n\n        public SpecificException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/error/BasicErrorPropagationTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.error;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport com.netflix.hystrix.exception.ExceptionNotWrappedByHystrix;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.MockitoAnnotations;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeoutException;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicErrorPropagationTest extends BasicHystrixTest {\n\n    private static final String COMMAND_KEY = \"getUserById\";\n\n    private static final Map<String, User> USERS;\n\n    static {\n        USERS = new HashMap<String, User>();\n        USERS.put(\"1\", new User(\"1\", \"user_1\"));\n        USERS.put(\"2\", new User(\"2\", \"user_2\"));\n        USERS.put(\"3\", new User(\"3\", \"user_3\"));\n    }\n\n    private UserService userService;\n\n    @MockitoAnnotations.Mock\n    private FailoverService failoverService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        MockitoAnnotations.initMocks(this);\n        userService = createUserService();\n        userService.setFailoverService(failoverService);\n    }\n\n    @Test(expected = BadRequestException.class)\n    public void testGetUserByBadId() throws NotFoundException {\n        try {\n            String badId = \"\";\n            userService.getUserById(badId);\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(COMMAND_KEY);\n            // will not affect metrics\n            assertFalse(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            // and will not trigger fallback logic\n            verify(failoverService, never()).getDefUser();\n        }\n    }\n\n    @Test(expected = NotFoundException.class)\n    public void testGetNonExistentUser() throws NotFoundException {\n        try {\n            userService.getUserById(\"4\"); // user with id 4 doesn't exist\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(COMMAND_KEY);\n            // will not affect metrics\n            assertFalse(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            // and will not trigger fallback logic\n            verify(failoverService, never()).getDefUser();\n        }\n    }\n\n    @Test // don't expect any exceptions because fallback must be triggered\n    public void testActivateUser() throws NotFoundException, ActivationException {\n        try {\n            userService.activateUser(\"1\"); // this method always throws ActivationException\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo activateUserCommand = getHystrixCommandByKey(\"activateUser\");\n            // will not affect metrics\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n            // and will not trigger fallback logic\n            verify(failoverService, atLeastOnce()).activate();\n        }\n    }\n\n    @Test(expected = RuntimeOperationException.class)\n    public void testBlockUser() throws NotFoundException, ActivationException, OperationException {\n        try {\n            userService.blockUser(\"1\"); // this method always throws ActivationException\n        } finally {\n            assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo activateUserCommand = getHystrixCommandByKey(\"blockUser\");\n            // will not affect metrics\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_FAILURE));\n        }\n    }\n\n    @Test(expected = NotFoundException.class)\n    public void testPropagateCauseException() throws NotFoundException {\n        userService.deleteUser(\"\");\n    }\n\n    @Test(expected = UserException.class)\n    public void testUserExceptionThrownFromCommand() {\n        userService.userFailureWithoutFallback();\n    }\n\n    @Test\n    public void testHystrixExceptionThrownFromCommand() {\n        try {\n            userService.timedOutWithoutFallback();\n        } catch (HystrixRuntimeException e) {\n            assertEquals(TimeoutException.class, e.getCause().getClass());\n        } catch (Throwable e) {\n            assertTrue(\"'HystrixRuntimeException' is expected exception.\", false);\n        }\n    }\n\n    @Test\n    public void testUserExceptionThrownFromFallback() {\n        try {\n            userService.userFailureWithFallback();\n        } catch (UserException e) {\n            assertEquals(1, e.level);\n        } catch (Throwable e) {\n            assertTrue(\"'UserException' is expected exception.\", false);\n        }\n    }\n\n    @Test\n    public void testUserExceptionThrownFromFallbackCommand() {\n        try {\n            userService.userFailureWithFallbackCommand();\n        } catch (UserException e) {\n            assertEquals(2, e.level);\n        } catch (Throwable e) {\n            assertTrue(\"'UserException' is expected exception.\", false);\n        }\n    }\n\n    @Test\n    public void testCommandAndFallbackErrorsComposition() {\n        try {\n            userService.commandAndFallbackErrorsComposition();\n        } catch (HystrixFlowException e) {\n            assertEquals(UserException.class, e.commandException.getClass());\n            assertEquals(UserException.class, e.fallbackException.getClass());\n\n            UserException commandException = (UserException) e.commandException;\n            UserException fallbackException = (UserException) e.fallbackException;\n            assertEquals(0, commandException.level);\n            assertEquals(1, fallbackException.level);\n\n\n        } catch (Throwable e) {\n            assertTrue(\"'HystrixFlowException' is expected exception.\", false);\n        }\n    }\n\n    @Test\n    public void testCommandWithFallbackThatFailsByTimeOut() {\n        try {\n            userService.commandWithFallbackThatFailsByTimeOut();\n        } catch (HystrixRuntimeException e) {\n            assertEquals(TimeoutException.class, e.getCause().getClass());\n        } catch (Throwable e) {\n            assertTrue(\"'HystrixRuntimeException' is expected exception.\", false);\n        }\n    }\n\n    @Test\n    public void testCommandWithNotWrappedExceptionAndNoFallback() {\n        try {\n            userService.throwNotWrappedCheckedExceptionWithoutFallback();\n            fail();\n        } catch (NotWrappedCheckedException e) {\n            // pass\n        } catch (Throwable e) {\n            fail(\"'NotWrappedCheckedException' is expected exception.\");\n        }finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"throwNotWrappedCheckedExceptionWithoutFallback\");\n            // record failure in metrics\n            assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            // and will not trigger fallback logic\n            verify(failoverService, never()).activate();\n        }\n    }\n\n    @Test\n    public void testCommandWithNotWrappedExceptionAndFallback() {\n        try {\n            userService.throwNotWrappedCheckedExceptionWithFallback();\n        } catch (NotWrappedCheckedException e) {\n            fail();\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"throwNotWrappedCheckedExceptionWithFallback\");\n            assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n            verify(failoverService).activate();\n        }\n    }\n\n    public static class UserService {\n\n        private FailoverService failoverService;\n\n        public void setFailoverService(FailoverService failoverService) {\n            this.failoverService = failoverService;\n        }\n\n        @HystrixCommand\n        public Object deleteUser(String id) throws NotFoundException {\n            throw new NotFoundException(\"\");\n        }\n\n        @HystrixCommand(\n                commandKey = COMMAND_KEY,\n                ignoreExceptions = {\n                        BadRequestException.class,\n                        NotFoundException.class\n                },\n                fallbackMethod = \"fallback\")\n        public User getUserById(String id) throws NotFoundException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                throw new NotFoundException(\"user with id: \" + id + \" not found\");\n            }\n            return USERS.get(id);\n        }\n\n\n        @HystrixCommand(\n                ignoreExceptions = {BadRequestException.class, NotFoundException.class},\n                fallbackMethod = \"activateFallback\")\n        public void activateUser(String id) throws NotFoundException, ActivationException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                throw new NotFoundException(\"user with id: \" + id + \" not found\");\n            }\n            // always throw this exception\n            throw new ActivationException(\"user cannot be activate\");\n        }\n\n        @HystrixCommand(\n                ignoreExceptions = {BadRequestException.class, NotFoundException.class},\n                fallbackMethod = \"blockUserFallback\")\n        public void blockUser(String id) throws NotFoundException, OperationException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                throw new NotFoundException(\"user with id: \" + id + \" not found\");\n            }\n            // always throw this exception\n            throw new OperationException(\"user cannot be blocked\");\n        }\n\n        private User fallback(String id) {\n            return failoverService.getDefUser();\n        }\n\n        private void activateFallback(String id) {\n            failoverService.activate();\n        }\n\n        @HystrixCommand(ignoreExceptions = {RuntimeException.class})\n        private void blockUserFallback(String id) {\n            throw new RuntimeOperationException(\"blockUserFallback has failed\");\n        }\n\n        private void validate(String val) throws BadRequestException {\n            if (val == null || val.length() == 0) {\n                throw new BadRequestException(\"parameter cannot be null ot empty\");\n            }\n        }\n\n        @HystrixCommand\n        void throwNotWrappedCheckedExceptionWithoutFallback() throws NotWrappedCheckedException {\n            throw new NotWrappedCheckedException();\n        }\n\n        @HystrixCommand(fallbackMethod = \"voidFallback\")\n        void throwNotWrappedCheckedExceptionWithFallback() throws NotWrappedCheckedException {\n            throw new NotWrappedCheckedException();\n        }\n\n        private void voidFallback(){\n            failoverService.activate();\n        }\n\n        /*********************************************************************************/\n\n        @HystrixCommand\n        String userFailureWithoutFallback() throws UserException {\n            throw new UserException();\n        }\n\n        @HystrixCommand(commandProperties = {@HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"1\")})\n        String timedOutWithoutFallback() {\n            return \"\";\n        }\n\n        /*********************************************************************************/\n\n        @HystrixCommand(fallbackMethod = \"userFailureWithFallback_f_0\")\n        String userFailureWithFallback() {\n            throw new UserException();\n        }\n\n        String userFailureWithFallback_f_0() {\n            throw new UserException(1);\n        }\n\n        /*********************************************************************************/\n\n        @HystrixCommand(fallbackMethod = \"userFailureWithFallbackCommand_f_0\")\n        String userFailureWithFallbackCommand() {\n            throw new UserException(0);\n        }\n\n        @HystrixCommand(fallbackMethod = \"userFailureWithFallbackCommand_f_1\")\n        String userFailureWithFallbackCommand_f_0() {\n            throw new UserException(1);\n        }\n\n        @HystrixCommand\n        String userFailureWithFallbackCommand_f_1() {\n            throw new UserException(2);\n        }\n\n        /*********************************************************************************/\n\n        @HystrixCommand(fallbackMethod = \"commandAndFallbackErrorsComposition_f_0\")\n        String commandAndFallbackErrorsComposition() {\n            throw new UserException();\n        }\n\n\n        String commandAndFallbackErrorsComposition_f_0(Throwable commandError) {\n            throw new HystrixFlowException(commandError, new UserException(1));\n        }\n\n        /*********************************************************************************/\n\n        @HystrixCommand(fallbackMethod = \"commandWithFallbackThatFailsByTimeOut_f_0\")\n        String commandWithFallbackThatFailsByTimeOut() {\n            throw new UserException(0);\n        }\n\n        @HystrixCommand(commandProperties = {@HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"1\")})\n        String commandWithFallbackThatFailsByTimeOut_f_0() {\n            return \"\";\n        }\n    }\n\n    private class FailoverService {\n        public User getDefUser() {\n            return new User(\"def\", \"def\");\n        }\n\n        public void activate() {\n        }\n    }\n\n    // exceptions\n    private static class NotFoundException extends Exception {\n        private NotFoundException(String message) {\n            super(message);\n        }\n    }\n\n    private static class BadRequestException extends RuntimeException {\n        private BadRequestException(String message) {\n            super(message);\n        }\n    }\n\n    private static class ActivationException extends Exception {\n        private ActivationException(String message) {\n            super(message);\n        }\n    }\n\n    private static class OperationException extends Throwable {\n        private OperationException(String message) {\n            super(message);\n        }\n    }\n\n    private static class RuntimeOperationException extends RuntimeException {\n        private RuntimeOperationException(String message) {\n            super(message);\n        }\n    }\n\n    private static class NotWrappedCheckedException extends Exception implements ExceptionNotWrappedByHystrix {\n    }\n\n    static class UserException extends RuntimeException {\n        final int level;\n\n        public UserException() {\n            this(0);\n        }\n\n        public UserException(int level) {\n            this.level = level;\n        }\n    }\n\n    static class HystrixFlowException extends RuntimeException {\n        final Throwable commandException;\n        final Throwable fallbackException;\n\n        public HystrixFlowException(Throwable commandException, Throwable fallbackException) {\n            this.commandException = commandException;\n            this.fallbackException = fallbackException;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/error/BasicObservableErrorPropagationTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.error;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.MockitoAnnotations;\nimport rx.Observable;\nimport rx.observers.TestSubscriber;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.*;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicObservableErrorPropagationTest extends BasicHystrixTest {\n\n    private static final String COMMAND_KEY = \"getUserById\";\n\n    private static final Map<String, User> USERS;\n\n    static {\n        USERS = new HashMap<String, User>();\n        USERS.put(\"1\", new User(\"1\", \"user_1\"));\n        USERS.put(\"2\", new User(\"2\", \"user_2\"));\n        USERS.put(\"3\", new User(\"3\", \"user_3\"));\n    }\n\n    private UserService userService;\n\n    @MockitoAnnotations.Mock\n    private FailoverService failoverService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        MockitoAnnotations.initMocks(this);\n        userService = createUserService();\n        userService.setFailoverService(failoverService);\n    }\n\n    @Test\n    public void testGetUserByBadId() throws NotFoundException {\n        try {\n            TestSubscriber<User> testSubscriber = new TestSubscriber<User>();\n\n            String badId = \"\";\n            userService.getUserById(badId).subscribe(testSubscriber);\n\n            testSubscriber.assertError(BadRequestException.class);\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(COMMAND_KEY);\n            // will not affect metrics\n            assertFalse(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            // and will not trigger fallback logic\n            verify(failoverService, never()).getDefUser();\n        }\n    }\n\n    @Test\n    public void testGetNonExistentUser() throws NotFoundException {\n        try {\n            TestSubscriber<User> testSubscriber = new TestSubscriber<User>();\n\n            userService.getUserById(\"4\").subscribe(testSubscriber); // user with id 4 doesn't exist\n\n            testSubscriber.assertError(NotFoundException.class);\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(COMMAND_KEY);\n            // will not affect metrics\n            assertFalse(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            // and will not trigger fallback logic\n            verify(failoverService, never()).getDefUser();\n        }\n    }\n\n    @Test // don't expect any exceptions because fallback must be triggered\n    public void testActivateUser() throws NotFoundException, ActivationException {\n        try {\n            userService.activateUser(\"1\").toBlocking().single(); // this method always throws ActivationException\n        } finally {\n            assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo activateUserCommand = getHystrixCommandByKey(\"activateUser\");\n            // will not affect metrics\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n            // and will not trigger fallback logic\n            verify(failoverService, atLeastOnce()).activate();\n        }\n    }\n\n    @Test\n    public void testBlockUser() throws NotFoundException, ActivationException, OperationException {\n        try {\n            TestSubscriber<Void> testSubscriber = new TestSubscriber<Void>();\n\n            userService.blockUser(\"1\").subscribe(testSubscriber); // this method always throws ActivationException\n\n            testSubscriber.assertError(Throwable.class);\n            assertTrue(testSubscriber.getOnErrorEvents().size() == 1);\n            assertTrue(testSubscriber.getOnErrorEvents().get(0).getCause() instanceof OperationException);\n        } finally {\n            assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n            com.netflix.hystrix.HystrixInvokableInfo activateUserCommand = getHystrixCommandByKey(\"blockUser\");\n            // will not affect metrics\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(activateUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_FAILURE));\n        }\n    }\n\n    @Test\n    public void testPropagateCauseException() throws NotFoundException {\n        TestSubscriber<Void> testSubscriber = new TestSubscriber<Void>();\n\n        userService.deleteUser(\"\").subscribe(testSubscriber);\n\n        testSubscriber.assertError(NotFoundException.class);\n    }\n\n    public static class UserService {\n\n        private FailoverService failoverService;\n\n        public void setFailoverService(FailoverService failoverService) {\n            this.failoverService = failoverService;\n        }\n\n        @HystrixCommand\n        public Observable<Void> deleteUser(String id) throws NotFoundException {\n            return Observable.error(new NotFoundException(\"\"));\n        }\n\n        @HystrixCommand(\n                commandKey = COMMAND_KEY,\n                ignoreExceptions = {\n                        BadRequestException.class,\n                        NotFoundException.class\n                },\n                fallbackMethod = \"fallback\")\n        public Observable<User> getUserById(String id) throws NotFoundException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                return Observable.error(new NotFoundException(\"user with id: \" + id + \" not found\"));\n            }\n            return Observable.just(USERS.get(id));\n        }\n\n\n        @HystrixCommand(\n                ignoreExceptions = {BadRequestException.class, NotFoundException.class},\n                fallbackMethod = \"activateFallback\")\n        public Observable<Void> activateUser(String id) throws NotFoundException, ActivationException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                return Observable.error(new NotFoundException(\"user with id: \" + id + \" not found\"));\n            }\n            // always throw this exception\n            return Observable.error(new ActivationException(\"user cannot be activate\"));\n        }\n\n        @HystrixCommand(\n                ignoreExceptions = {BadRequestException.class, NotFoundException.class},\n                fallbackMethod = \"blockUserFallback\")\n        public Observable<Void> blockUser(String id) throws NotFoundException, OperationException {\n            validate(id);\n            if (!USERS.containsKey(id)) {\n                return Observable.error(new NotFoundException(\"user with id: \" + id + \" not found\"));\n            }\n            // always throw this exception\n            return Observable.error(new OperationException(\"user cannot be blocked\"));\n        }\n\n        private Observable<User> fallback(String id) {\n            return failoverService.getDefUser();\n        }\n\n        private Observable<Void> activateFallback(String id) {\n            return failoverService.activate();\n        }\n\n        @HystrixCommand(ignoreExceptions = {RuntimeException.class})\n        private Observable<Void> blockUserFallback(String id) {\n            return Observable.error(new RuntimeOperationException(\"blockUserFallback has failed\"));\n        }\n\n        private void validate(String val) throws BadRequestException {\n            if (val == null || val.length() == 0) {\n                throw new BadRequestException(\"parameter cannot be null ot empty\");\n            }\n        }\n    }\n\n    private class FailoverService {\n        public Observable<User> getDefUser() {\n            return Observable.just(new User(\"def\", \"def\"));\n        }\n\n        public Observable<Void> activate() {\n            return Observable.empty();\n        }\n    }\n\n    // exceptions\n    private static class NotFoundException extends Exception {\n        private NotFoundException(String message) {\n            super(message);\n        }\n    }\n\n    private static class BadRequestException extends RuntimeException {\n        private BadRequestException(String message) {\n            super(message);\n        }\n    }\n\n    private static class ActivationException extends Exception {\n        private ActivationException(String message) {\n            super(message);\n        }\n    }\n\n    private static class OperationException extends Throwable {\n        private OperationException(String message) {\n            super(message);\n        }\n    }\n\n    private static class RuntimeOperationException extends RuntimeException {\n        private RuntimeOperationException(String message) {\n            super(message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/fallback/BasicCommandFallbackTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.fallback;\n\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;\nimport com.netflix.hystrix.contrib.javanica.command.AsyncResult;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.Domain;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport org.apache.commons.lang3.Validate;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Observable;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\npublic abstract class BasicCommandFallbackTest extends BasicHystrixTest {\n\n    private UserService userService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n    }\n\n    @Test\n    public void testGetUserAsyncWithFallback() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserAsync(\" \", \"name: \");\n\n        assertEquals(\"def\", f1.get().getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"getUserAsync\", command.getCommandKey().name());\n\n        // confirm that 'getUserAsync' command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that fallback waw successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n\n    }\n\n    @Test\n    public void testGetUserSyncWithFallback() {\n        User u1 = userService.getUserSync(\" \", \"name: \");\n\n        assertEquals(\"def\", u1.getName());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n\n        assertEquals(\"getUserSync\", command.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that fallback was successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n\n    }\n\n\n    /**\n     * * **************************** *\n     * * * TEST FALLBACK COMMANDS * *\n     * * **************************** *\n     */\n    @Test\n    public void testGetUserAsyncWithFallbackCommand() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserAsyncFallbackCommand(\" \", \"name: \");\n\n        assertEquals(\"def\", f1.get().getName());\n\n        assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> getUserAsyncFallbackCommand = getHystrixCommandByKey(\n                \"getUserAsyncFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo firstFallbackCommand = getHystrixCommandByKey(\"firstFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo secondFallbackCommand = getHystrixCommandByKey(\"secondFallbackCommand\");\n\n        assertEquals(\"getUserAsyncFallbackCommand\", getUserAsyncFallbackCommand.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(getUserAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // confirm that first fallback has failed\n        assertTrue(firstFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that second fallback was successful\n        assertTrue(secondFallbackCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetUserAsyncFallbackAsyncCommand() throws ExecutionException, InterruptedException {\n        Future<User> f1 = userService.getUserAsyncFallbackAsyncCommand(\" \", \"name: \");\n\n        assertEquals(\"def\", f1.get().getName());\n\n        assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> getUserAsyncFallbackAsyncCommand = getHystrixCommandByKey(\n                \"getUserAsyncFallbackAsyncCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo firstAsyncFallbackCommand = getHystrixCommandByKey(\"firstAsyncFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo secondAsyncFallbackCommand = getHystrixCommandByKey(\"secondAsyncFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo thirdAsyncFallbackCommand = getHystrixCommandByKey(\"thirdAsyncFallbackCommand\");\n        assertEquals(\"getUserAsyncFallbackAsyncCommand\", getUserAsyncFallbackAsyncCommand.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(getUserAsyncFallbackAsyncCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // confirm that first fallback has failed\n        assertTrue(firstAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that second fallback was successful\n        assertTrue(secondAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n\n        assertTrue(thirdAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(thirdAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetUserSyncWithFallbackCommand() {\n        User u1 = userService.getUserSyncFallbackCommand(\" \", \"name: \");\n\n        assertEquals(\"def\", u1.getName());\n        assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> getUserSyncFallbackCommand = getHystrixCommandByKey(\n                \"getUserSyncFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo firstFallbackCommand = getHystrixCommandByKey(\"firstFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo secondFallbackCommand = getHystrixCommandByKey(\"secondFallbackCommand\");\n\n        assertEquals(\"getUserSyncFallbackCommand\", getUserSyncFallbackCommand.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(getUserSyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // confirm that first fallback has failed\n        assertTrue(firstFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that second fallback was successful\n        assertTrue(secondFallbackCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testAsyncCommandWithAsyncFallbackCommand() throws ExecutionException, InterruptedException {\n        Future<User> userFuture = userService.asyncCommandWithAsyncFallbackCommand(\"\", \"\");\n        User user = userFuture.get();\n        assertEquals(\"def\", user.getId());\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> asyncCommandWithAsyncFallbackCommand = getHystrixCommandByKey(\"asyncCommandWithAsyncFallbackCommand\");\n        com.netflix.hystrix.HystrixInvokableInfo asyncFallbackCommand = getHystrixCommandByKey(\"asyncFallbackCommand\");\n        // confirm that command has failed\n        assertTrue(asyncCommandWithAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(asyncCommandWithAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        // and that second fallback was successful\n        assertTrue(asyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    public void testAsyncCommandWithAsyncFallback() {\n        userService.asyncCommandWithAsyncFallback(\"\", \"\");\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    public void testCommandWithWrongFallbackReturnType() {\n        userService.commandWithWrongFallbackReturnType(\"\", \"\");\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    public void testAsyncCommandWithWrongFallbackReturnType() {\n        userService.asyncCommandWithWrongFallbackReturnType(\"\", \"\");\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    public void testCommandWithWrongFallbackParams() {\n        userService.commandWithWrongFallbackParams(\"1\", \"2\");\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    public void testCommandWithFallbackReturnSuperType() {\n        userService.commandWithFallbackReturnSuperType(\"\", \"\");\n    }\n\n    @Test\n    public void testCommandWithFallbackReturnSubType() {\n        User user = (User) userService.commandWithFallbackReturnSubType(\"\", \"\");\n        assertEquals(\"def\", user.getName());\n    }\n\n    @Test\n    public void testCommandWithFallbackWithAdditionalParameter() {\n        User user = userService.commandWithFallbackWithAdditionalParameter(\"\", \"\");\n        assertEquals(\"def\", user.getName());\n    }\n\n    @Test(expected = HystrixBadRequestException.class)\n    public void testCommandThrowsHystrixBadRequestExceptionWithNoCause() {\n        try {\n            userService.commandThrowsHystrixBadRequestExceptionWithNoCause(null, null);\n        } finally {\n            HystrixInvokableInfo<?> asyncCommandWithAsyncFallbackCommand = getHystrixCommandByKey(\"commandThrowsHystrixBadRequestExceptionWithNoCause\");\n            assertFalse(asyncCommandWithAsyncFallbackCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        }\n    }\n\n    @Test\n    public void testFallbackMissing(){\n        try {\n            userService.getUserWithoutFallback(null, null);\n        } catch (Exception e) {}\n\n        HystrixInvokableInfo<?> command = getHystrixCommandByKey(\"getUserWithoutFallback\");\n        assertTrue(\"expected event: FALLBACK_MISSING\", command.getExecutionEvents().contains(HystrixEventType.FALLBACK_MISSING));\n    }\n\n    public static class UserService {\n\n        @HystrixCommand\n        public User getUserWithoutFallback(final String id, final String name) {\n            validate(id, name);\n            return new User(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public Future<User> getUserAsync(final String id, final String name) {\n            validate(id, name); // validate logic can be inside and outside of AsyncResult#invoke method\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    // validate(id, name); possible put validation logic here, in case of any exception a fallback method will be invoked\n                    return new User(id, name + id); // it should be network call\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public User getUserSync(String id, String name) {\n            validate(id, name);\n            return new User(id, name + id); // it should be network call\n        }\n\n        private User fallback(String id, String name) {\n            return new User(\"def\", \"def\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"firstFallbackCommand\")\n        public Future<User> getUserAsyncFallbackCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    validate(id, name);\n                    return new User(id, name + id); // it should be network call\n                }\n            };\n        }\n\n\n        @HystrixCommand(fallbackMethod = \"firstFallbackCommand\")\n        public User getUserSyncFallbackCommand(String id, String name) {\n            validate(id, name);\n            return new User(id, name + id); // it should be network call\n        }\n\n        // FALLBACK COMMANDS METHODS:\n        // This fallback methods will be processed as hystrix commands\n\n        @HystrixCommand(fallbackMethod = \"secondFallbackCommand\")\n        private User firstFallbackCommand(String id, String name) {\n            validate(id, name);\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand(fallbackMethod = \"staticFallback\")\n        private User secondFallbackCommand(String id, String name) {\n            validate(id, name);\n            return new User(id, name + id); // it should be network call\n        }\n\n        @HystrixCommand(fallbackMethod = \"firstAsyncFallbackCommand\")\n        public Future<User> getUserAsyncFallbackAsyncCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    throw new RuntimeException(\"getUserAsyncFallbackAsyncCommand failed\");\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"secondAsyncFallbackCommand\")\n        private Future<User> firstAsyncFallbackCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    throw new RuntimeException(\"firstAsyncFallbackCommand failed\");\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"thirdAsyncFallbackCommand\")\n        private Future<User> secondAsyncFallbackCommand(final String id, final String name, final Throwable e) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    if (\"firstAsyncFallbackCommand failed\".equals(e.getMessage())) {\n                        throw new RuntimeException(\"secondAsyncFallbackCommand failed\");\n                    }\n                    return new User(id, name + id);\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackWithAdditionalParam\")\n        private Future<User> thirdAsyncFallbackCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    throw new RuntimeException(\"thirdAsyncFallbackCommand failed\");\n                }\n            };\n        }\n\n        private User fallbackWithAdditionalParam(final String id, final String name, final Throwable e) {\n            if (!\"thirdAsyncFallbackCommand failed\".equals(e.getMessage())) {\n                throw new RuntimeException(\"fallbackWithAdditionalParam failed\");\n            }\n            return new User(\"def\", \"def\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"asyncFallbackCommand\", commandProperties = {\n                @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"100000\")\n        })\n        public Future<User> asyncCommandWithAsyncFallbackCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    validate(id, name);\n                    return new User(id, name + id); // it should be network call\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"asyncFallback\", commandProperties = {\n                @HystrixProperty(name = \"execution.isolation.thread.timeoutInMilliseconds\", value = \"100000\")\n        })\n        public Future<User> asyncCommandWithAsyncFallback(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    validate(id, name);\n                    return new User(id, name + id); // it should be network call\n                }\n            };\n        }\n\n        public Future<User> asyncFallback(final String id, final String name) {\n            return Observable.just(new User(\"def\", \"def\")).toBlocking().toFuture();\n        }\n\n        @HystrixCommand\n        public Future<User> asyncFallbackCommand(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(\"def\", \"def\"); // it should be network call\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackWithAdditionalParameter\")\n        public User commandWithFallbackWithAdditionalParameter(final String id, final String name) {\n            validate(id, name);\n            return new User(id, name + id);\n        }\n\n        public User fallbackWithAdditionalParameter(final String id, final String name, Throwable e) {\n            if (e == null) {\n                throw new RuntimeException(\"exception should be not null\");\n            }\n            return new User(\"def\", \"def\");\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackWithStringReturnType\")\n        public User commandWithWrongFallbackReturnType(final String id, final String name) {\n            validate(id, name);\n            return new User(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackWithStringReturnType\")\n        public Future<User> asyncCommandWithWrongFallbackReturnType(final String id, final String name) {\n            return new AsyncResult<User>() {\n                @Override\n                public User invoke() {\n                    return new User(\"def\", \"def\"); // it should be network call\n                }\n            };\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackWithoutParameters\")\n        public User commandWithWrongFallbackParams(final String id, final String name) {\n            return new User(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackReturnSubTypeOfDomain\")\n        public Domain commandWithFallbackReturnSubType(final String id, final String name) {\n            validate(id, name);\n            return new User(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallbackReturnSuperTypeOfDomain\")\n        public User commandWithFallbackReturnSuperType(final String id, final String name) {\n            validate(id, name);\n            return new User(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"staticFallback\")\n        public User commandThrowsHystrixBadRequestExceptionWithNoCause(final String id, final String name){\n            throw new HystrixBadRequestException(\"invalid arguments\");\n        }\n\n        private User fallbackReturnSubTypeOfDomain(final String id, final String name) {\n            return new User(\"def\", \"def\");\n        }\n\n        private Domain fallbackReturnSuperTypeOfDomain(final String id, final String name) {\n            return new User(\"def\", \"def\");\n        }\n\n        private String fallbackWithStringReturnType(final String id, final String name) {\n            return null;\n        }\n\n        private User fallbackWithoutParameters() {\n            return null;\n        }\n\n        private User staticFallback(String id, String name) {\n            return new User(\"def\", \"def\");\n        }\n\n        private void validate(String id, String name) {\n            Validate.notBlank(id);\n            Validate.notBlank(name);\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/fallback/BasicDefaultFallbackTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.fallback;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport org.junit.Before;\nimport org.junit.Test;\n\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil.\n */\npublic abstract class BasicDefaultFallbackTest extends BasicHystrixTest {\n\n    private ServiceWithDefaultFallback serviceWithDefaultFallback;\n    private ServiceWithDefaultCommandFallback serviceWithDefaultCommandFallback;\n\n    protected abstract ServiceWithDefaultFallback createServiceWithDefaultFallback();\n\n    protected abstract ServiceWithDefaultCommandFallback serviceWithDefaultCommandFallback();\n\n    @Before\n    public void setUp() throws Exception {\n        serviceWithDefaultFallback = createServiceWithDefaultFallback();\n        serviceWithDefaultCommandFallback = serviceWithDefaultCommandFallback();\n    }\n\n    @Test\n    public void testClassScopeDefaultFallback() {\n        String res = serviceWithDefaultFallback.requestString(\"\");\n        assertEquals(ServiceWithDefaultFallback.DEFAULT_RESPONSE, res);\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"requestString\", command.getCommandKey().name());\n\n        // confirm that 'requestString' command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that default fallback waw successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testSpecificCommandFallbackOverridesDefault() {\n        Integer res = serviceWithDefaultFallback.commandWithSpecificFallback(\"\");\n        assertEquals(Integer.valueOf(res), res);\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"commandWithSpecificFallback\", command.getCommandKey().name());\n\n        // confirm that 'commandWithSpecificFallback' command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that default fallback waw successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n\n    @Test\n    public void testCommandScopeDefaultFallback() {\n        Long res = serviceWithDefaultFallback.commandWithDefaultFallback(1L);\n        assertEquals(Long.valueOf(0L), res);\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest()\n                .getAllExecutedCommands().iterator().next();\n        assertEquals(\"commandWithDefaultFallback\", command.getCommandKey().name());\n\n        // confirm that 'requestString' command has failed\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that default fallback waw successful\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testClassScopeCommandDefaultFallback() {\n        String res = serviceWithDefaultCommandFallback.requestString(\"\");\n        assertEquals(ServiceWithDefaultFallback.DEFAULT_RESPONSE, res);\n\n\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> requestStringCommand = getHystrixCommandByKey(\"requestString\");\n        com.netflix.hystrix.HystrixInvokableInfo fallback = getHystrixCommandByKey(\"classDefaultFallback\");\n\n        assertEquals(\"requestString\", requestStringCommand.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(requestStringCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(requestStringCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        // confirm that fallback was successful\n        assertTrue(fallback.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testCommandScopeCommandDefaultFallback() {\n        Long res = serviceWithDefaultCommandFallback.commandWithDefaultFallback(1L);\n        assertEquals(Long.valueOf(0L), res);\n\n\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> requestStringCommand = getHystrixCommandByKey(\"commandWithDefaultFallback\");\n        com.netflix.hystrix.HystrixInvokableInfo fallback = getHystrixCommandByKey(\"defaultCommandFallback\");\n\n        assertEquals(\"commandWithDefaultFallback\", requestStringCommand.getCommandKey().name());\n        // confirm that command has failed\n        assertTrue(requestStringCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(requestStringCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        // confirm that fallback was successful\n        assertTrue(fallback.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    // case when class level default fallback\n    @DefaultProperties(defaultFallback = \"classDefaultFallback\")\n    public static class ServiceWithDefaultFallback {\n        static final String DEFAULT_RESPONSE = \"class_def\";\n\n        @HystrixCommand\n        public String requestString(String str) {\n            throw new RuntimeException();\n        }\n\n        public String classDefaultFallback() {\n            return DEFAULT_RESPONSE;\n        }\n\n        @HystrixCommand(defaultFallback = \"defaultCommandFallback\")\n        Long commandWithDefaultFallback(long l){\n            throw new RuntimeException();\n        }\n\n        Long defaultCommandFallback(){\n            return 0L;\n        }\n\n        @HystrixCommand(fallbackMethod = \"specificFallback\")\n        Integer commandWithSpecificFallback(String str) {\n            throw new RuntimeException();\n        }\n\n        Integer specificFallback(String str) {\n            return 0;\n        }\n    }\n\n    // class level default fallback is annotated with @HystrixCommand and should be executed as Hystrix command\n    @DefaultProperties(defaultFallback = \"classDefaultFallback\")\n    public static class ServiceWithDefaultCommandFallback {\n        static final String DEFAULT_RESPONSE = \"class_def\";\n\n        @HystrixCommand\n        public String requestString(String str) {\n            throw new RuntimeException();\n        }\n\n        @HystrixCommand\n        public String classDefaultFallback() {\n            return DEFAULT_RESPONSE;\n        }\n\n        @HystrixCommand(defaultFallback = \"defaultCommandFallback\")\n        Long commandWithDefaultFallback(long l){\n            throw new RuntimeException();\n        }\n\n        @HystrixCommand(fallbackMethod = \"defaultCommandFallback\")\n        Long defaultCommandFallback(){\n            return 0L;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/fallback/BasicGenericFallbackTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.common.fallback;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport junitparams.JUnitParamsRunner;\nimport junitparams.Parameters;\nimport org.junit.ClassRule;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.helpers.MessageFormatter;\nimport org.springframework.test.context.junit4.rules.SpringClassRule;\nimport org.springframework.test.context.junit4.rules.SpringMethodRule;\nimport rx.Completable;\n\nimport java.io.Serializable;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Set;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(JUnitParamsRunner.class)\npublic abstract class BasicGenericFallbackTest extends BasicHystrixTest {\n\n    @ClassRule\n    public static final SpringClassRule SCR = new SpringClassRule();\n    @Rule\n    public final SpringMethodRule springMethodRule = new SpringMethodRule();\n\n    protected abstract <T> T createProxy(Class<T> t);\n\n\n    public Object[] methodGenericDefinitionSuccess() {\n        return new Object[]{\n                new Object[]{MethodGenericDefinitionSuccessCase0.class},\n                new Object[]{MethodGenericDefinitionSuccessCase1.class},\n                new Object[]{MethodGenericDefinitionSuccessCase2.class},\n                new Object[]{MethodGenericDefinitionSuccessCase3.class},\n                new Object[]{MethodGenericDefinitionSuccessCase4.class},\n                new Object[]{MethodGenericDefinitionSuccessCase5.class},\n                new Object[]{MethodGenericDefinitionSuccessCase6.class},\n                new Object[]{MethodGenericDefinitionSuccessCase7.class},\n        };\n    }\n\n    public Object[] methodGenericDefinitionFailure() {\n        return new Object[]{\n                new Object[]{MethodGenericDefinitionFailureCase0.class},\n                new Object[]{MethodGenericDefinitionFailureCase1.class},\n                new Object[]{MethodGenericDefinitionFailureCase2.class},\n                new Object[]{MethodGenericDefinitionFailureCase3.class},\n                new Object[]{MethodGenericDefinitionFailureCase4.class},\n                new Object[]{MethodGenericDefinitionFailureCase5.class},\n                new Object[]{MethodGenericDefinitionFailureCase6.class},\n                new Object[]{MethodGenericDefinitionFailureCase7.class},\n                new Object[]{MethodGenericDefinitionFailureCase8.class},\n                new Object[]{MethodGenericDefinitionFailureCase9.class},\n                new Object[]{MethodGenericDefinitionFailureCase10.class},\n                new Object[]{MethodGenericDefinitionFailureCase11.class},\n\n        };\n    }\n\n    public Object[] classGenericDefinitionSuccess() {\n        return new Object[]{\n                new Object[]{ClassGenericDefinitionSuccessCase0.class},\n                new Object[]{ClassGenericDefinitionSuccessCase1.class},\n        };\n    }\n\n\n    public Object[] classGenericDefinitionFailure() {\n        return new Object[]{\n                new Object[]{ClassGenericDefinitionFailureCase0.class},\n                new Object[]{ClassGenericDefinitionFailureCase1.class},\n        };\n    }\n\n    @Test\n    @Parameters(method = \"methodGenericDefinitionSuccess\")\n    public void testMethodGenericDefinitionSuccess(Class<?> type) {\n        testXKindGenericDefinitionSuccess(type);\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    @Parameters(method = \"methodGenericDefinitionFailure\")\n    public void testMethodGenericDefinitionFailure(Class<?> type) {\n        Object p = createProxy(type);\n        executeCommand(p);\n    }\n\n    @Test\n    @Parameters(method = \"classGenericDefinitionSuccess\")\n    public void testClassGenericDefinitionSuccess(Class<?> type) {\n        testXKindGenericDefinitionSuccess(type);\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    @Parameters(method = \"classGenericDefinitionFailure\")\n    public void testClassGenericDefinitionFailure(Class<?> type) {\n        Object p = createProxy(type);\n        executeCommand(p);\n    }\n\n    private void testXKindGenericDefinitionSuccess(Class<?> type) {\n        Object p = createProxy(type);\n        try {\n            executeCommand(p);\n\n            HystrixInvokableInfo<?> command = getHystrixCommandByKey(\"command\");\n\n            assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n\n        } catch (FallbackDefinitionException e) {\n            throw new AssertionError(MessageFormatter.format(\"Case class '{}' has failed. Reason:\\n{}\", type.getCanonicalName(), e).getMessage());\n        }\n    }\n\n    /* ====================================================================== */\n    /* ===================== GENERIC METHOD DEFINITIONS ===================== */\n    /* =========================== SUCCESS CASES ============================ */\n\n    public static class MethodGenericDefinitionSuccessCase0 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> T command() { throw new IllegalStateException(); }\n        private <T> T fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase1 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable> T command() { throw new IllegalStateException(); }\n        private <T extends Serializable> T fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase2 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable, T1 extends T> T1 command() { throw new IllegalStateException(); }\n        private <T extends Serializable, T1 extends T> T1 fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase3 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase4 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase5 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase6 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> GenericEntity<T> command() { throw new IllegalStateException(); }\n        private <T> GenericEntity<T> fallback() { return new GenericEntity<T>(); }\n    }\n\n    public static class MethodGenericDefinitionSuccessCase7 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<? super Serializable> command() { throw new IllegalStateException(); }\n        private GenericEntity<? super Serializable> fallback() { return null; }\n    }\n\n\n    /* ====================================================================== */\n    /* ===================== GENERIC METHOD DEFINITIONS ===================== */\n    /* =========================== FAILURE CASES ============================ */\n\n    public static class MethodGenericDefinitionFailureCase0 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> T command() { throw new IllegalStateException(); }\n        private String fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase1 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable> T command() { throw new IllegalStateException(); }\n        private <T> T fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase2 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable> T command() { throw new IllegalStateException(); }\n        private <T extends Comparable> T fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase3 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable, T1 extends T> GenericEntity<T1> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase4 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase5 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> command() { throw new IllegalStateException(); }\n        private <T extends Serializable & Comparable, T1 extends GenericEntity<String>> GenericEntity<T1> fallback() { return null;}\n    }\n\n    public static class MethodGenericDefinitionFailureCase6 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> GenericEntity<T> command() { throw new IllegalStateException(); }\n        private GenericEntity<String> fallback() { return new GenericEntity<String>(); }\n    }\n\n    public static class MethodGenericDefinitionFailureCase7 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> Set<T> command() { throw new IllegalStateException(); }\n        private <T> List<T> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase8 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> GenericEntity<Set<T>> command() { throw new IllegalStateException(); }\n        private <T> GenericEntity<List<T>> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase9 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public <T> GenericEntity<List<Set<T>>> command() { throw new IllegalStateException(); }\n        private <T> GenericEntity<List<List<T>>> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase10 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<? super Serializable> command() { throw new IllegalStateException(); }\n        private GenericEntity<? super Comparable> fallback() { return null; }\n    }\n\n    public static class MethodGenericDefinitionFailureCase11 {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public Completable command() { throw new IllegalStateException(); }\n        private void fallback() { return; }\n    }\n\n    /* ====================================================================== */\n    /* ===================== GENERIC CLASS DEFINITIONS =====+================ */\n    /* =========================== SUCCESS CASES ============================ */\n\n    public static class ClassGenericDefinitionSuccessCase0<T> {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<T> command() { throw new IllegalStateException(); }\n        private GenericEntity<T> fallback() { return new GenericEntity<T>(); }\n    }\n\n    public static class ClassGenericDefinitionSuccessCase1<T extends Serializable> {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<T> command() { throw new IllegalStateException(); }\n        private GenericEntity<T> fallback() { return new GenericEntity<T>(); }\n    }\n\n    /* ====================================================================== */\n    /* ===================== GENERIC CLASS DEFINITIONS =====+================ */\n    /* =========================== FAILURE CASES ============================ */\n\n    public static class ClassGenericDefinitionFailureCase0<T> {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<T> command() { throw new IllegalStateException(); }\n        private <T> GenericEntity<T> fallback() { return new GenericEntity<T>(); }\n    }\n\n    public static class ClassGenericDefinitionFailureCase1<T extends Serializable> {\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public GenericEntity<T> command() { throw new IllegalStateException(); }\n        private <T extends Serializable> GenericEntity<T> fallback() { return new GenericEntity<T>(); }\n    }\n\n    public static class GenericEntity<T> {\n    }\n\n    private static Object executeCommand(Object proxy) {\n        try {\n            Method method = proxy.getClass().getDeclaredMethod(\"command\");\n            return method.invoke(proxy);\n        } catch (InvocationTargetException e) {\n            Throwable t = e.getCause();\n            if (t instanceof FallbackDefinitionException) {\n                throw (FallbackDefinitionException) t;\n            } else throw new RuntimeException(e);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/observable/BasicObservableTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.common.observable;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode;\nimport com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Completable;\nimport rx.Observable;\nimport rx.Observer;\nimport rx.Single;\nimport rx.Subscriber;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\n\nimport static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil\n */\npublic abstract class BasicObservableTest extends BasicHystrixTest {\n\n\n    private UserService userService;\n\n    protected abstract UserService createUserService();\n\n    @Before\n    public void setUp() throws Exception {\n        userService = createUserService();\n    }\n\n    @Test\n    public void testGetUserByIdSuccess() {\n        // blocking\n        Observable<User> observable = userService.getUser(\"1\", \"name: \");\n        assertEquals(\"name: 1\", observable.toBlocking().single().getName());\n\n        // non-blocking\n        // - this is a verbose anonymous inner-class approach and doesn't do assertions\n        Observable<User> fUser = userService.getUser(\"1\", \"name: \");\n        fUser.subscribe(new Observer<User>() {\n\n            @Override\n            public void onCompleted() {\n                // nothing needed here\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                e.printStackTrace();\n            }\n\n            @Override\n            public void onNext(User v) {\n                System.out.println(\"onNext: \" + v);\n            }\n\n        });\n\n        Observable<User> fs = userService.getUser(\"1\", \"name: \");\n        fs.subscribe(new Action1<User>() {\n\n            @Override\n            public void call(User user) {\n                assertEquals(\"name: 1\", user.getName());\n            }\n        });\n        assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getUser\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetCompletableUser(){\n        userService.getCompletableUser(\"1\", \"name: \");\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getCompletableUser\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetCompletableUserWithRegularFallback() {\n        Completable completable = userService.getCompletableUserWithRegularFallback(null, \"name: \");\n        completable.<User>toObservable().subscribe(new Action1<User>() {\n            @Override\n            public void call(User user) {\n                assertEquals(\"default_id\", user.getId());\n            }\n        });\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getCompletableUserWithRegularFallback\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetCompletableUserWithRxFallback() {\n        Completable completable = userService.getCompletableUserWithRxFallback(null, \"name: \");\n        completable.<User>toObservable().subscribe(new Action1<User>() {\n            @Override\n            public void call(User user) {\n                assertEquals(\"default_id\", user.getId());\n            }\n        });\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getCompletableUserWithRxFallback\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetSingleUser() {\n        final String id = \"1\";\n        Single<User> user = userService.getSingleUser(id, \"name: \");\n        user.subscribe(new Action1<User>() {\n            @Override\n            public void call(User user) {\n                assertEquals(id, user.getId());\n            }\n        });\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getSingleUser\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n    @Test\n    public void testGetSingleUserWithRegularFallback(){\n        Single<User> user = userService.getSingleUserWithRegularFallback(null, \"name: \");\n        user.subscribe(new Action1<User>() {\n            @Override\n            public void call(User user) {\n                assertEquals(\"default_id\", user.getId());\n            }\n        });\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getSingleUserWithRegularFallback\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetSingleUserWithRxFallback(){\n        Single<User> user = userService.getSingleUserWithRxFallback(null, \"name: \");\n        user.subscribe(new Action1<User>() {\n            @Override\n            public void call(User user) {\n                assertEquals(\"default_id\", user.getId());\n            }\n        });\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getSingleUserWithRxFallback\");\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetUserWithRegularFallback() {\n        final User exUser = new User(\"def\", \"def\");\n        Observable<User> userObservable = userService.getUserRegularFallback(\" \", \"\");\n        // blocking\n        assertEquals(exUser, userObservable.toBlocking().single());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getUserRegularFallback\");\n        // confirm that command has failed\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that fallback was successful\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetUserWithRxFallback() {\n        final User exUser = new User(\"def\", \"def\");\n\n        // blocking\n        assertEquals(exUser, userService.getUserRxFallback(\" \", \"\").toBlocking().single());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey(\"getUserRxFallback\");\n        // confirm that command has failed\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        // and that fallback was successful\n        assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n    }\n\n    @Test\n    public void testGetUserWithRxCommandFallback() {\n        final User exUser = new User(\"def\", \"def\");\n\n        // blocking\n        Observable<User> userObservable = userService.getUserRxCommandFallback(\" \", \"\");\n        assertEquals(exUser, userObservable.toBlocking().single());\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        com.netflix.hystrix.HystrixInvokableInfo getUserRxCommandFallback = getHystrixCommandByKey(\"getUserRxCommandFallback\");\n        com.netflix.hystrix.HystrixInvokableInfo rxCommandFallback = getHystrixCommandByKey(\"rxCommandFallback\");\n        // confirm that command has failed\n        assertTrue(getUserRxCommandFallback.getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(getUserRxCommandFallback.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));\n        // and that fallback command was successful\n        assertTrue(rxCommandFallback.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n    }\n\n\n    public static class UserService {\n\n        private User regularFallback(String id, String name) {\n            return new User(\"def\", \"def\");\n        }\n\n        private Observable<User> rxFallback(String id, String name) {\n            return Observable.just(new User(\"def\", \"def\"));\n        }\n\n        @HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER)\n        private Observable<User> rxCommandFallback(String id, String name, Throwable throwable) {\n            if (throwable instanceof GetUserException && \"getUserRxCommandFallback has failed\".equals(throwable.getMessage())) {\n                return Observable.just(new User(\"def\", \"def\"));\n            } else {\n                throw new IllegalStateException();\n            }\n\n        }\n\n        @HystrixCommand\n        public Observable<User> getUser(final String id, final String name) {\n            validate(id, name, \"getUser has failed\");\n            return createObservable(id, name);\n        }\n\n        @HystrixCommand\n        public Completable getCompletableUser(final String id, final String name) {\n            validate(id, name, \"getCompletableUser has failed\");\n            return createObservable(id, name).toCompletable();\n        }\n\n        @HystrixCommand(fallbackMethod = \"completableUserRegularFallback\")\n        public Completable getCompletableUserWithRegularFallback(final String id, final String name) {\n            return getCompletableUser(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"completableUserRxFallback\")\n        public Completable getCompletableUserWithRxFallback(final String id, final String name) {\n            return getCompletableUser(id, name);\n        }\n\n        public User completableUserRegularFallback(final String id, final String name) {\n            return new User(\"default_id\", \"default_name\");\n        }\n\n        public Completable completableUserRxFallback(final String id, final String name) {\n            return Completable.fromCallable(new Func0<User>() {\n                @Override\n                public User call() {\n                    return new User(\"default_id\", \"default_name\");\n                }\n            });\n        }\n\n        @HystrixCommand\n        public Single<User> getSingleUser(final String id, final String name) {\n            validate(id, name, \"getSingleUser has failed\");\n            return createObservable(id, name).toSingle();\n        }\n\n        @HystrixCommand(fallbackMethod = \"singleUserRegularFallback\")\n        public Single<User> getSingleUserWithRegularFallback(final String id, final String name) {\n            return getSingleUser(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"singleUserRxFallback\")\n        public Single<User> getSingleUserWithRxFallback(final String id, final String name) {\n            return getSingleUser(id, name);\n        }\n\n        User singleUserRegularFallback(final String id, final String name) {\n            return new User(\"default_id\", \"default_name\");\n        }\n\n        Single<User> singleUserRxFallback(final String id, final String name) {\n            return createObservable(\"default_id\", \"default_name\").toSingle();\n        }\n\n        @HystrixCommand(fallbackMethod = \"regularFallback\", observableExecutionMode = ObservableExecutionMode.LAZY)\n        public Observable<User> getUserRegularFallback(final String id, final String name) {\n            validate(id, name, \"getUser has failed\");\n            return createObservable(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"rxFallback\")\n        public Observable<User> getUserRxFallback(final String id, final String name) {\n            validate(id, name, \"getUserRxFallback has failed\");\n            return createObservable(id, name);\n        }\n\n        @HystrixCommand(fallbackMethod = \"rxCommandFallback\", observableExecutionMode = ObservableExecutionMode.LAZY)\n        public Observable<User> getUserRxCommandFallback(final String id, final String name) {\n            validate(id, name, \"getUserRxCommandFallback has failed\");\n            return createObservable(id, name);\n        }\n\n\n        private Observable<User> createObservable(final String id, final String name) {\n            return Observable.create(new Observable.OnSubscribe<User>() {\n                @Override\n                public void call(Subscriber<? super User> observer) {\n                    try {\n                        if (!observer.isUnsubscribed()) {\n                            observer.onNext(new User(id, name + id));\n                            observer.onCompleted();\n                        }\n                    } catch (Exception e) {\n                        observer.onError(e);\n                    }\n                }\n            });\n        }\n\n        private void validate(String id, String name, String errorMsg) {\n            if (StringUtils.isBlank(id) || StringUtils.isBlank(name)) {\n                throw new GetUserException(errorMsg);\n            }\n        }\n\n        private static final class GetUserException extends RuntimeException {\n            public GetUserException(String message) {\n                super(message);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/cache/CacheTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.cache;\n\nimport com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect;\nimport com.netflix.hystrix.contrib.javanica.test.common.cache.BasicCacheTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Test to check cache implementation based on JSR-107.\n *\n * @author dmgcodevil\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CacheTest.CacheTestConfig.class})\npublic class CacheTest extends BasicCacheTest {\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n\n    @Override\n    protected UserService createUserService() {\n        return applicationContext.getBean(UserService.class);\n    }\n\n    /**\n     * Spring configuration.\n     */\n    @Configurable\n    public static class CacheTestConfig {\n        @Bean\n        @Scope(value = \"prototype\")\n        public UserService userService() {\n            return new UserService();\n        }\n\n        @Bean\n        public HystrixCacheAspect hystrixCacheAspect() {\n            return new HystrixCacheAspect();\n        }\n    }\n\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/collapser/CollapserTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.collapser;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.collapser.BasicCollapserTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * This test covers \"Request Collapsing\" functionality.\n * <p/>\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#Collapsing\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CollapserTest.CollapserTestConfig.class})\npublic class CollapserTest extends BasicCollapserTest {\n\n    @Autowired\n    private BasicCollapserTest.UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n\n    /**\n     * Spring configuration.\n     */\n    @Configurable\n    public static class CollapserTestConfig {\n\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/command/CommandTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.command;\n\n\nimport com.netflix.hystrix.contrib.javanica.test.common.command.BasicCommandTest;\nimport com.netflix.hystrix.contrib.javanica.test.common.domain.User;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * This test covers \"Hystrix command\" functionality.\n * <p/>\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#Synchronous-Execution\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#Asynchronous-Execution\n */\npublic abstract class CommandTest extends BasicCommandTest {\n\n    @Autowired private BasicCommandTest.UserService userService;\n    @Autowired private BasicCommandTest.AdvancedUserService advancedUserService;\n    @Autowired private BasicCommandTest.GenericService<String, Long, User> genericUserService;\n\n    @Override\n    protected BasicCommandTest.UserService createUserService() {\n        return userService;\n    }\n\n    @Override\n    protected BasicCommandTest.AdvancedUserService createAdvancedUserServiceService() {\n        return advancedUserService;\n    }\n\n    @Override\n    protected BasicCommandTest.GenericService<String, Long, User> createGenericUserService() {\n        return genericUserService;\n    }\n\n    @Configurable\n    public static class CommandTestConfig {\n\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n\n        @Bean\n        public AdvancedUserService advancedUserService() {\n            return new AdvancedUserService();\n        }\n\n        @Bean\n        public GenericService<String, Long, User> genericUserService() {\n            return new GenericUserService();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/command/cglib/CommandCGlibProxyTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.command.cglib;\n\nimport com.netflix.hystrix.contrib.javanica.test.spring.command.CommandTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CommandTest.CommandTestConfig.class})\npublic class CommandCGlibProxyTest extends CommandTest {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/command/jdk/CommandJdkProxyTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.command.jdk;\n\n\nimport com.netflix.hystrix.contrib.javanica.test.spring.command.CommandTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopJdkConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopJdkConfig.class, CommandTest.CommandTestConfig.class})\npublic class CommandJdkProxyTest extends CommandTest {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopCglibConfig.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.conf;\n\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\n\n@Configurable\n@Import(SpringApplicationContext.class)\n@EnableAspectJAutoProxy(proxyTargetClass = true)\npublic class AopCglibConfig {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopJdkConfig.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.conf;\n\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\n\n@Configurable\n@Import(SpringApplicationContext.class)\n@EnableAspectJAutoProxy\npublic class AopJdkConfig {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/AopLoadTimeWeavingConfig.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.conf;\n\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.EnableLoadTimeWeaving;\nimport org.springframework.context.annotation.Import;\n\n@Configurable\n@Import(SpringApplicationContext.class)\n@EnableAspectJAutoProxy\n@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)\npublic class AopLoadTimeWeavingConfig {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/conf/SpringApplicationContext.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.conf;\n\nimport com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\n\n@Configurable\n@ComponentScan(\"com.netflix.hystrix.contrib.javanica.test.spring\")\npublic class SpringApplicationContext {\n\n    @Bean\n    public HystrixCommandAspect hystrixAspect() {\n        return new HystrixCommandAspect();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/configuration/collapser/CollapserPropertiesTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.configuration.collapser;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.collapser.BasicCollapserPropertiesTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CollapserPropertiesTest.CollapserPropertiesTestConfig.class})\npublic class CollapserPropertiesTest extends BasicCollapserPropertiesTest {\n\n    @Autowired\n    private UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n\n    @Configurable\n    public static class CollapserPropertiesTestConfig {\n\n        @Bean\n        public BasicCollapserPropertiesTest.UserService userService() {\n            return new UserService();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/configuration/command/CommandDefaultPropertiesTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.configuration.command;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.command.BasicCommandDefaultPropertiesTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CommandDefaultPropertiesTest.Config.class})\npublic class CommandDefaultPropertiesTest extends BasicCommandDefaultPropertiesTest {\n\n    @Autowired\n    private Service service;\n\n    @Override\n    protected Service createService() {\n        return service;\n    }\n\n    @Configurable\n    public static class Config {\n        @Bean\n        @Scope(value = \"prototype\")\n        public BasicCommandDefaultPropertiesTest.Service service() {\n            return new BasicCommandDefaultPropertiesTest.Service();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/configuration/command/CommandPropertiesTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.configuration.command;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.command.BasicCommandPropertiesTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CommandPropertiesTest.CommandPropertiesTestConfig.class})\npublic class CommandPropertiesTest extends BasicCommandPropertiesTest {\n\n    @Autowired\n    private BasicCommandPropertiesTest.UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n\n    @Configurable\n    public static class CommandPropertiesTestConfig {\n\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/configuration/fallback/FallbackDefaultPropertiesTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.configuration.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.configuration.fallback.BasicFallbackDefaultPropertiesTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, FallbackDefaultPropertiesTest.Config.class})\npublic class FallbackDefaultPropertiesTest extends BasicFallbackDefaultPropertiesTest {\n\n    @Autowired\n    private Service service;\n\n    @Override\n    protected Service createService() {\n        return service;\n    }\n\n    @Configurable\n    public static class Config {\n        @Bean\n        public BasicFallbackDefaultPropertiesTest.Service service() {\n            return new BasicFallbackDefaultPropertiesTest.Service();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/error/DefaultIgnoreExceptionsTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.error;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicDefaultIgnoreExceptionsTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, DefaultIgnoreExceptionsTest.DefaultIgnoreExceptionsTestConfig.class})\npublic class DefaultIgnoreExceptionsTest extends BasicDefaultIgnoreExceptionsTest {\n\n\n    @Autowired\n    private BasicDefaultIgnoreExceptionsTest.Service service;\n\n    @Override\n    protected BasicDefaultIgnoreExceptionsTest.Service createService() {\n        return service;\n    }\n\n    @Configurable\n    public static class DefaultIgnoreExceptionsTestConfig {\n\n        @Bean\n        public BasicDefaultIgnoreExceptionsTest.Service userService() {\n            return new BasicDefaultIgnoreExceptionsTest.Service();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/error/DefaultRaiseHystrixExceptionsTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.error;\n\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicDefaultRaiseHystrixExceptionsTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\n\n/**\n * Created by Mike Cowan\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, DefaultRaiseHystrixExceptionsTest.DefaultRaiseHystrixExceptionsTestConfig.class})\npublic class DefaultRaiseHystrixExceptionsTest extends BasicDefaultRaiseHystrixExceptionsTest {\n\n    @Autowired\n    private BasicDefaultRaiseHystrixExceptionsTest.Service service;\n\n    @Override\n    protected BasicDefaultRaiseHystrixExceptionsTest.Service createService() {\n        return service;\n    }\n\n    @Configurable\n    public static class DefaultRaiseHystrixExceptionsTestConfig {\n\n        @Bean\n        public BasicDefaultRaiseHystrixExceptionsTest.Service userService() {\n            return new BasicDefaultRaiseHystrixExceptionsTest.Service();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/error/ErrorPropagationTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.error;\n\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicErrorPropagationTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Test covers \"Error Propagation\" functionality.\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#ErrorPropagation\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, ErrorPropagationTest.ErrorPropagationTestConfig.class})\npublic class ErrorPropagationTest extends BasicErrorPropagationTest {\n\n\n    @Autowired\n    private BasicErrorPropagationTest.UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n\n    @Configurable\n    public static class ErrorPropagationTestConfig {\n\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n    }\n    \n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/error/ObservableErrorPropagationTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.error;\n\n\nimport com.netflix.hystrix.contrib.javanica.test.common.error.BasicObservableErrorPropagationTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Test covers \"Error Propagation\" functionality.\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#ErrorPropagation\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, ObservableErrorPropagationTest.ErrorPropagationTestConfig.class})\npublic class ObservableErrorPropagationTest extends BasicObservableErrorPropagationTest {\n\n\n    @Autowired\n    private UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n\n    @Configurable\n    public static class ErrorPropagationTestConfig {\n\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/fallback/CommandFallbackTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.fallback.BasicCommandFallbackTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Test covers \"Fallback\" functionality.\n * <p/>\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#Fallback\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, CommandFallbackTest.CommandTestConfig.class})\npublic class CommandFallbackTest extends BasicCommandFallbackTest {\n\n    @Autowired\n    private UserService userService;\n\n    @Override\n    protected BasicCommandFallbackTest.UserService createUserService() {\n        return userService;\n    }\n\n    @Configurable\n    public static class CommandTestConfig {\n        @Bean\n        public UserService userService() {\n            return new UserService();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/fallback/DefaultFallbackTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.fallback.BasicDefaultFallbackTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, DefaultFallbackTest.Config.class})\npublic class DefaultFallbackTest extends BasicDefaultFallbackTest {\n\n    @Autowired\n    private ServiceWithDefaultFallback serviceWithDefaultFallback;\n    @Autowired\n    private ServiceWithDefaultCommandFallback serviceWithDefaultCommandFallback;\n\n\n    @Override\n    protected ServiceWithDefaultFallback createServiceWithDefaultFallback() {\n        return serviceWithDefaultFallback;\n    }\n\n    @Override\n    protected ServiceWithDefaultCommandFallback serviceWithDefaultCommandFallback() {\n        return serviceWithDefaultCommandFallback;\n    }\n\n    @Configurable\n    public static class Config {\n        @Bean\n        public ServiceWithDefaultFallback serviceWithDefaultFallback() {\n            return new ServiceWithDefaultFallback();\n        }\n\n        @Bean\n        public ServiceWithDefaultCommandFallback serviceWithDefaultCommandFallback() {\n            return new ServiceWithDefaultCommandFallback();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/fallback/GenericFallbackTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.fallback.BasicGenericFallbackTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.ContextConfiguration;\n\n/**\n * Created by dmgcodevil.\n */\n@ContextConfiguration(classes = {AopCglibConfig.class})\npublic class GenericFallbackTest extends BasicGenericFallbackTest {\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Override\n    protected <T> T createProxy(Class<T> t) {\n        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();\n        return beanFactory.createBean(t);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/fallback/InheritedFallbackTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.test.spring.fallback;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.fallback.BasicCommandFallbackTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, InheritedFallbackTest.CommandTestConfig.class})\npublic class InheritedFallbackTest extends BasicCommandFallbackTest {\n\n    @Autowired\n    private UserService userService;\n\n    @Override\n    protected BasicCommandFallbackTest.UserService createUserService() {\n        return userService;\n    }\n\n    @Configurable\n    public static class CommandTestConfig {\n        @Bean\n        public UserService userService() {\n            return new SubClass();\n        }\n    }\n\n    public static class SubClass extends BasicCommandFallbackTest.UserService {\n    }\n\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/spring/observable/ObservableTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.test.spring.observable;\n\nimport com.netflix.hystrix.contrib.javanica.test.common.observable.BasicObservableTest;\nimport com.netflix.hystrix.contrib.javanica.test.spring.conf.AopCglibConfig;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Configurable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * Test covers \"Reactive Execution\" functionality.\n * https://github.com/Netflix/Hystrix/wiki/How-To-Use#Reactive-Execution\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(classes = {AopCglibConfig.class, ObservableTest.ObservableTestConfig.class})\npublic class ObservableTest extends BasicObservableTest {\n\n    @Autowired\n    private UserService userService;\n\n    @Override\n    protected UserService createUserService() {\n        return userService;\n    }\n\n    @Configurable\n    public static class ObservableTestConfig {\n\n        @Bean\n        public BasicObservableTest.UserService userService() {\n            return new UserService();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/FallbackMethodTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util;\n\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.utils.MethodProvider;\nimport com.tngtech.java.junit.dataprovider.DataProvider;\nimport com.tngtech.java.junit.dataprovider.DataProviderRunner;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport java.lang.reflect.Method;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(DataProviderRunner.class)\npublic class FallbackMethodTest {\n\n    @Test\n    public void testGetExtendedFallback() throws NoSuchMethodException {\n        // given\n        Method command = Service.class.getDeclaredMethod(\"command\", String.class, Integer.class);\n        // when\n        Method extFallback = MethodProvider.getInstance().getFallbackMethod(Service.class, command).getMethod();\n        // then\n        assertParamsTypes(extFallback, String.class, Integer.class, Throwable.class);\n    }\n\n    @Test\n    @DataProvider({\"true\", \"false\"})\n    public void testGetFallbackForExtendedCommand(boolean extended) throws NoSuchMethodException {\n        // given\n        Method extFallback = Service.class.getDeclaredMethod(\"extCommand\", String.class, Integer.class, Throwable.class);\n        // when\n        Method fallback = MethodProvider.getInstance().getFallbackMethod(Service.class, extFallback, extended).getMethod();\n        // then\n        assertParamsTypes(fallback, String.class, Integer.class, Throwable.class);\n    }\n\n    public void testGetFallbackForExtendedCommandV2() throws NoSuchMethodException {\n        // given\n        Method extFallback = Service.class.getDeclaredMethod(\"extCommandV2\", String.class, Integer.class, Throwable.class);\n        // when\n        Method fallback = MethodProvider.getInstance().getFallbackMethod(Service.class, extFallback, true).getMethod();\n        // then\n        assertParamsTypes(fallback, String.class, Integer.class);\n    }\n\n    public void testGetFallbackForExtendedCommandV2_extendedParameterFalse() throws NoSuchMethodException {\n        // given\n        Method extFallback = Service.class.getDeclaredMethod(\"extCommandV2\", String.class, Integer.class, Throwable.class);\n        // when\n        Method fallback = MethodProvider.getInstance().getFallbackMethod(Service.class, extFallback, false).getMethod();\n        // then\n        assertNull(fallback);\n    }\n\n\n    private static void assertParamsTypes(Method method, Class<?>... expected) {\n        assertEquals(expected.length, method.getParameterTypes().length);\n        Class<?>[] actual = method.getParameterTypes();\n        assertArrayEquals(expected, actual);\n    }\n\n    private static class Common {\n        private String fallback(String s, Integer i) {\n            return null;\n        }\n\n        private String fallbackV2(String s, Integer i) {\n            return null;\n        }\n    }\n\n    private static class Service extends Common{\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public String command(String s, Integer i) {\n            return null;\n        }\n\n        @HystrixCommand(fallbackMethod = \"fallback\")\n        public String extCommand(String s, Integer i, Throwable throwable) {\n            return null;\n        }\n\n\n        @HystrixCommand(fallbackMethod = \"fallbackV2\")\n        public String extCommandV2(String s, Integer i, Throwable throwable) {\n            return null;\n        }\n\n\n        public String fallback(String s, Integer i, Throwable throwable) {\n            return null;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/FallbackMethodValidationTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util;\n\nimport com.google.common.base.Throwables;\nimport com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;\nimport com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;\nimport com.netflix.hystrix.contrib.javanica.utils.FallbackMethod;\nimport com.tngtech.java.junit.dataprovider.DataProvider;\nimport com.tngtech.java.junit.dataprovider.DataProviderRunner;\nimport com.tngtech.java.junit.dataprovider.UseDataProvider;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport rx.Observable;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.Future;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(DataProviderRunner.class)\npublic class FallbackMethodValidationTest {\n\n\n    @DataProvider\n    public static Object[][] fail() {\n        // @formatter:off\n        return new Object[][]{\n                // sync execution\n                {getMethod(\"commandReturnPlainTypeLong\"), getMethod(\"fallbackReturnPlainTypeString\")},\n                {getMethod(\"commandReturnPlainTypeChild\"), getMethod(\"fallbackReturnPlainTypeParent\")},\n                {getMethod(\"commandReturnGenericTypeParent\"), getMethod(\"fallbackReturnGenericTypeChild\")},\n                {getMethod(\"commandReturnGenericTypeChild\"), getMethod(\"fallbackReturnGenericTypeParent\")},\n                {getMethod(\"commandReturnGenericTypeChildParent\"), getMethod(\"fallbackReturnGenericTypeParentChild\")},\n                {getMethod(\"commandReturnGenericTypeParentChild\"), getMethod(\"fallbackReturnGenericTypeChildParent\")},\n                {getMethod(\"commandReturnGenericNestedTypeParentChildParent\"), getMethod(\"commandReturnGenericNestedTypeParentParentParent\")},\n\n                // async execution\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackCommandReturnFutureChild\")},\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackReturnFutureParent\")},\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackReturnChild\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackReturnFutureParent\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackCommandReturnFutureParent\")},\n\n                // observable execution\n                {getMethod(\"fallbackReturnObservableParent\"), getMethod(\"fallbackReturnObservableChild\")},\n                {getMethod(\"fallbackReturnObservableParent\"), getMethod(\"fallbackCommandReturnObservableChild\")},\n                {getMethod(\"fallbackReturnObservableParent\"), getMethod(\"fallbackReturnChild\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackReturnObservableParent\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackCommandReturnObservableParent\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackReturnObservableChild\")},\n                {getMethod(\"commandReturnParent\"), getMethod(\"fallbackCommandReturnObservableChild\")},\n        };\n        // @formatter:on\n    }\n\n    @DataProvider\n    public static Object[][] success() {\n        // @formatter:off\n        return new Object[][]{\n                // sync execution\n                {getMethod(\"commandReturnPlainTypeLong\"), getMethod(\"fallbackReturnPlainTypeLong\")},\n                {getMethod(\"commandReturnPlainTypeParent\"), getMethod(\"fallbackReturnPlainTypeChild\")},\n                {getMethod(\"commandReturnPlainTypeParent\"), getMethod(\"fallbackReturnPlainTypeParent\")},\n                {getMethod(\"commandReturnGenericTypeChild\"), getMethod(\"fallbackReturnGenericTypeChild\")},\n                {getMethod(\"commandReturnGenericNestedTypeParentChildParent\"), getMethod(\"fallbackReturnGenericNestedTypeParentChildParent\")},\n\n\n                // async execution\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackCommandReturnFutureParent\")},\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackCommandReturnParent\")},\n                {getMethod(\"commandReturnFutureParent\"), getMethod(\"fallbackReturnParent\")},\n\n                // observable execution\n                {getMethod(\"commandReturnObservableParent\"), getMethod(\"fallbackReturnObservableParent\")},\n                {getMethod(\"commandReturnObservableParent\"), getMethod(\"fallbackCommandReturnObservableParent\")},\n                {getMethod(\"commandReturnObservableParent\"), getMethod(\"fallbackReturnParent\")},\n\n        };\n        // @formatter:on\n    }\n\n    @Test(expected = FallbackDefinitionException.class)\n    @UseDataProvider(\"fail\")\n    public void testValidateBadFallbackReturnType(Method commandMethod, Method fallbackMethod) {\n        new FallbackMethod(fallbackMethod).validateReturnType(commandMethod);\n    }\n\n    @UseDataProvider(\"success\")\n    public void testValidateCorrectFallbackReturnType(Method commandMethod, Method fallbackMethod) {\n        new FallbackMethod(fallbackMethod).validateReturnType(commandMethod);\n    }\n\n    private static Method getMethod(String name) {\n        try {\n            return Service.class.getDeclaredMethod(name);\n        } catch (NoSuchMethodException e) {\n            throw Throwables.propagate(e);\n        }\n    }\n\n    // @formatter:off\n    private static class Service {\n        // Sync execution\n        public Parent commandReturnPlainTypeParent() {return null;}\n        public Child commandReturnPlainTypeChild() {return null;}\n        public Parent fallbackReturnPlainTypeParent() {return null;}\n        public Child fallbackReturnPlainTypeChild() {return null;}\n        public Long commandReturnPlainTypeLong() {return null;}\n        public Long fallbackReturnPlainTypeLong() {return null;}\n        public String fallbackReturnPlainTypeString() {return null;}\n        public GType<Parent> commandReturnGenericTypeParent() {return null;}\n        public GType<Child> commandReturnGenericTypeChild() {return null;}\n        public GType<Parent> fallbackReturnGenericTypeParent() {return null;}\n        public GType<Child> fallbackReturnGenericTypeChild() {return null;}\n        public GDoubleType<Parent, Child> commandReturnGenericTypeParentChild() {return null;}\n        public GDoubleType<Child, Parent> commandReturnGenericTypeChildParent() {return null;}\n        public GDoubleType<Parent, Child> fallbackReturnGenericTypeParentChild() {return null;}\n        public GDoubleType<Child, Parent> fallbackReturnGenericTypeChildParent() {return null;}\n        public GType<GType<GDoubleType<GType<GDoubleType<Parent, Child>>, Parent>>> commandReturnGenericNestedTypeParentChildParent() {return null;}\n        public GType<GType<GDoubleType<GType<GDoubleType<Parent, Parent>>, Parent>>> commandReturnGenericNestedTypeParentParentParent() {return null;}\n        public GType<GType<GDoubleType<GType<GDoubleType<Parent, Child>>, Parent>>> fallbackReturnGenericNestedTypeParentChildParent() {return null;}\n\n        // Async execution\n        Future<Parent> commandReturnFutureParent() {return null;}\n        Parent commandReturnParent() {return null;}\n\n        Parent fallbackReturnParent() {return null;}\n        Child fallbackReturnChild() {return null;}\n        Future<Parent> fallbackReturnFutureParent() {return null;}\n        Future<Child> fallbackReturnFutureChild() {return null;}\n\n        @HystrixCommand Parent fallbackCommandReturnParent() {return null;}\n        @HystrixCommand Child fallbackCommandReturnChild() {return null;}\n        @HystrixCommand Future<Parent> fallbackCommandReturnFutureParent() {return null;}\n        @HystrixCommand Future<Child> fallbackCommandReturnFutureChild() {return null;}\n\n        // Observable execution\n        Observable<Parent> commandReturnObservableParent() {return null;}\n\n        Observable<Parent> fallbackReturnObservableParent() {return null;}\n        Observable<Child> fallbackReturnObservableChild() {return null;}\n\n        @HystrixCommand Observable<Parent> fallbackCommandReturnObservableParent() {return null;}\n        @HystrixCommand Observable<Child> fallbackCommandReturnObservableChild() {return null;}\n    }\n    // @formatter:on\n\n\n\n\n    private interface GType<T> {\n    }\n\n    private interface GDoubleType<T1, T2> {\n\n    }\n\n    private static class Parent {\n\n    }\n\n    private static class Child extends Parent {\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/GetMethodTest.java",
    "content": "package com.netflix.hystrix.contrib.javanica.util;\n\nimport com.google.common.base.Optional;\nimport com.netflix.hystrix.contrib.javanica.utils.MethodProvider;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\n/**\n * Created by dmgcodevil.\n */\n@RunWith(Parameterized.class)\npublic class GetMethodTest {\n\n    private String methodName;\n    private Class<?>[] parametersTypes;\n\n    @Parameterized.Parameters\n    public static Collection<Object[]> data() {\n        return Arrays.asList(new Object[][] {\n                { \"foo\", new Class<?>[]{ String.class } },\n                { \"bar\", new Class<?>[]{ Integer.class } }\n        });\n    }\n\n    public GetMethodTest(String methodName, Class<?>[] parametersTypes) {\n        this.methodName = methodName;\n        this.parametersTypes = parametersTypes;\n    }\n\n    @Test\n    public void testGetMethodFoo(){\n       Optional<Method> method =  MethodProvider.getInstance().getMethod(C.class, methodName, parametersTypes);\n\n        assertTrue(method.isPresent());\n        assertEquals(methodName, method.get().getName());\n    }\n\n\n    public static class A { void foo(String  in) {} }\n    public static class B extends A { void bar(Integer in) {} }\n    public static class C extends B{ }\n\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/Child.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\n/**\n * Created by dmgcodevil.\n */\npublic class Child extends Parent {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/GenericInterface.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\n/**\n * Created by dmgcodevil\n */\npublic interface GenericInterface<P1, R extends Parent> {\n\n\n    R foo(P1 p1);\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/GenericInterfaceImpl.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\n/**\n * Created by dmgcodevil\n */\npublic class GenericInterfaceImpl implements GenericInterface<Child, Parent> {\n\n\n    public Child foo(SubChild c) {\n        return null;\n    }\n\n    @Override\n    public Child foo(Child c) {\n        return null;\n    }\n\n    public Child foo(Parent c) {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/Parent.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\n\npublic class Parent {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/SubChild.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\n/**\n * Created by dmgcodevil.\n */\npublic class SubChild extends Child {\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/util/bridge/UnbridgeMethodTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.javanica.util.bridge;\n\nimport com.netflix.hystrix.contrib.javanica.utils.MethodProvider;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\n/**\n * Created by dmgcodevil\n */\npublic class UnbridgeMethodTest {\n\n    @Test\n    public void testUnbridgeFoo() throws NoSuchMethodException, IOException, ClassNotFoundException {\n        // given\n        Method bridgeMethod = getBridgeMethod(GenericInterfaceImpl.class, \"foo\");\n        assertNotNull(bridgeMethod);\n        // when\n        Method genMethod = MethodProvider.getInstance().unbride(bridgeMethod, GenericInterfaceImpl.class);\n        // then\n        assertNotNull(bridgeMethod);\n        assertReturnType(Child.class, genMethod);\n        assertParamsTypes(genMethod, Child.class);\n    }\n\n    private static Method getBridgeMethod(Class<?> type, String methodName) {\n        for (Method method : type.getDeclaredMethods()) {\n            if (method.isBridge() && method.getName().equals(methodName)) {\n                return method;\n            }\n        }\n        return null;\n    }\n\n    private static void assertReturnType(Class<?> expected, Method method) {\n        assertEquals(expected, method.getReturnType());\n    }\n\n    private static void assertParamsTypes(Method method, Class<?>... expected) {\n        assertEquals(expected.length, method.getParameterTypes().length);\n        Class<?>[] actual = method.getParameterTypes();\n        assertArrayEquals(expected, actual);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/resources/dummy.txt",
    "content": "====\n    Copyright 2016 Netflix, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n====\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-javanica/src/test/resources/log4j.properties",
    "content": "#\n# Copyright 2016 Netflix, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Define the root logger with appender console\nlog4j.rootLogger = ERROR, CONSOLE\n\n# Define the console appender\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\n\n# Define the layout for console appender\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.conversionPattern=%m%n\n\nlog4j.logger.com.netflix.hystrix.contrib.javanica=DEBUG\n"
  },
  {
    "path": "hystrix-contrib/hystrix-junit/build.gradle",
    "content": "dependencies {\n  api project(':hystrix-core')\n  api \"junit:junit:4.11\"\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-junit/src/main/java/com/hystrix/junit/HystrixRequestContextRule.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.hystrix.junit;\n\nimport com.netflix.hystrix.Hystrix;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.rules.ExternalResource;\n\n/**\n * JUnit rule to be used to simplify tests that require a HystrixRequestContext.\n *\n * Example of usage:\n *\n * <blockquote>\n * <pre>\n *     @Rule\n *     public HystrixRequestContextRule context = new HystrixRequestContextRule();\n * </pre>\n * </blockquote>\n *\n */\npublic final class HystrixRequestContextRule extends ExternalResource {\n    private HystrixRequestContext context;\n\n    @Override\n    protected void before() {\n        this.context = HystrixRequestContext.initializeContext();\n        Hystrix.reset();\n    }\n\n    @Override\n    protected void after() {\n        if (this.context != null) {\n            this.context.shutdown();\n            this.context = null;\n        }\n    }\n\n    public HystrixRequestContext context() {\n        return this.context;\n    }\n\n    public void reset() {\n        after();\n        before();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-junit/src/test/java/com/hystrix/junit/HystrixRequestContextRuleTest.java",
    "content": "package com.hystrix.junit;\n\nimport org.hamcrest.CoreMatchers;\nimport org.hamcrest.MatcherAssert;\nimport org.junit.Rule;\nimport org.junit.Test;\n\npublic final class HystrixRequestContextRuleTest {\n    @Rule\n    public HystrixRequestContextRule request = new HystrixRequestContextRule();\n\n    @Test\n    public void initsContext() {\n        MatcherAssert.assertThat(this.request.context(), CoreMatchers.notNullValue());\n    }\n\n    @Test\n    public void manuallyShutdownContextDontBreak() {\n        this.request.after();\n        this.request.after();\n        MatcherAssert.assertThat(this.request.context(), CoreMatchers.nullValue());\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/README.md",
    "content": "# hystrix-metrics-event-stream\n\nThis module exposes metrics in a [text/event-stream](https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events) formatted stream that continues as long as a client holds the connection.\n\nEach HystrixCommand instance will emit data such as this (without line breaks):\n\n```json\ndata: {\n  \"type\": \"HystrixCommand\",\n  \"name\": \"PlaylistGet\",\n  \"group\": \"PlaylistGet\",\n  \"currentTime\": 1355239617628,\n  \"isCircuitBreakerOpen\": false,\n  \"errorPercentage\": 0,\n  \"errorCount\": 0,\n  \"requestCount\": 121,\n  \"rollingCountCollapsedRequests\": 0,\n  \"rollingCountExceptionsThrown\": 0,\n  \"rollingCountFailure\": 0,\n  \"rollingCountFallbackFailure\": 0,\n  \"rollingCountFallbackRejection\": 0,\n  \"rollingCountFallbackSuccess\": 0,\n  \"rollingCountResponsesFromCache\": 69,\n  \"rollingCountSemaphoreRejected\": 0,\n  \"rollingCountShortCircuited\": 0,\n  \"rollingCountSuccess\": 121,\n  \"rollingCountThreadPoolRejected\": 0,\n  \"rollingCountTimeout\": 0,\n  \"currentConcurrentExecutionCount\": 0,\n  \"latencyExecute_mean\": 13,\n  \"latencyExecute\": {\n    \"0\": 3,\n    \"25\": 6,\n    \"50\": 8,\n    \"75\": 14,\n    \"90\": 26,\n    \"95\": 37,\n    \"99\": 75,\n    \"99.5\": 92,\n    \"100\": 252\n  },\n  \"latencyTotal_mean\": 15,\n  \"latencyTotal\": {\n    \"0\": 3,\n    \"25\": 7,\n    \"50\": 10,\n    \"75\": 18,\n    \"90\": 32,\n    \"95\": 43,\n    \"99\": 88,\n    \"99.5\": 160,\n    \"100\": 253\n  },\n  \"propertyValue_circuitBreakerRequestVolumeThreshold\": 20,\n  \"propertyValue_circuitBreakerSleepWindowInMilliseconds\": 5000,\n  \"propertyValue_circuitBreakerErrorThresholdPercentage\": 50,\n  \"propertyValue_circuitBreakerForceOpen\": false,\n  \"propertyValue_circuitBreakerForceClosed\": false,\n  \"propertyValue_circuitBreakerEnabled\": true,\n  \"propertyValue_executionIsolationStrategy\": \"THREAD\",\n  \"propertyValue_executionIsolationThreadTimeoutInMilliseconds\": 800,\n  \"propertyValue_executionIsolationThreadInterruptOnTimeout\": true,\n  \"propertyValue_executionIsolationThreadPoolKeyOverride\": null,\n  \"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\": 20,\n  \"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\": 10,\n  \"propertyValue_metricsRollingStatisticalWindowInMilliseconds\": 10000,\n  \"propertyValue_requestCacheEnabled\": true,\n  \"propertyValue_requestLogEnabled\": true,\n  \"reportingHosts\": 1\n}\n```\n\nHystrixThreadPool instances will emit data such as this:\n\n```json\ndata:\n{\n  \"currentPoolSize\": 30,\n  \"rollingMaxActiveThreads\": 13,\n  \"currentActiveCount\": 0,\n  \"currentCompletedTaskCount\": 4459519,\n  \"propertyValue_queueSizeRejectionThreshold\": 30,\n  \"type\": \"HystrixThreadPool\",\n  \"reportingHosts\": 3,\n  \"propertyValue_metricsRollingStatisticalWindowInMilliseconds\": 30000,\n  \"name\": \"ABClient\",\n  \"currentLargestPoolSize\": 30,\n  \"currentCorePoolSize\": 30,\n  \"currentQueueSize\": 0,\n  \"currentTaskCount\": 4459519,\n  \"rollingCountThreadsExecuted\": 919,\n  \"currentMaximumPoolSize\": 30\n}\n```\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-metrics-event-stream%22).\n\nExample for Maven ([lookup latest version](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-metrics-event-stream%22)):\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-metrics-event-stream</artifactId>\n    <version>1.4.10</version>\n</dependency>\n```\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-metrics-event-stream\" rev=\"1.4.10\" />\n```\n\n# Installation\n\n1) Include hystrix-metrics-event-stream-*.jar in your classpath (such as /WEB-INF/lib)  \n2) Add the following to your application web.xml:  \n\n```xml\n  <servlet>\n\t\t<description></description>\n\t\t<display-name>HystrixMetricsStreamServlet</display-name>\n\t\t<servlet-name>HystrixMetricsStreamServlet</servlet-name>\n\t\t<servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>\n\t</servlet>\n\n\t<servlet-mapping>\n\t\t<servlet-name>HystrixMetricsStreamServlet</servlet-name>\n\t\t<url-pattern>/hystrix.stream</url-pattern>\n\t</servlet-mapping>\n```\n\n# Test\n\nTo test your installation you can use curl like this:\n\n```\n$ curl http://hostname:port/appname/hystrix.stream\n\ndata: {\"rollingCountFailure\":0,\"propertyValue_executionIsolationThreadInterruptOnTimeout\":true,\"rollingCountTimeout\":0,\"rollingCountExceptionsThrown\":0,\"rollingCountFallbackSuccess\":0,\"errorCount\":0,\"type\":\"HystrixCommand\",\"propertyValue_circuitBreakerEnabled\":true,\"reportingHosts\":1,\"latencyTotal\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"currentConcurrentExecutionCount\":0,\"rollingCountSemaphoreRejected\":0,\"rollingCountFallbackRejection\":0,\"rollingCountShortCircuited\":0,\"rollingCountResponsesFromCache\":0,\"propertyValue_circuitBreakerForceClosed\":false,\"name\":\"IdentityCookieAuthSwitchProfile\",\"propertyValue_executionIsolationThreadPoolKeyOverride\":\"null\",\"rollingCountSuccess\":0,\"propertyValue_requestLogEnabled\":true,\"requestCount\":0,\"rollingCountCollapsedRequests\":0,\"errorPercentage\":0,\"propertyValue_circuitBreakerSleepWindowInMilliseconds\":5000,\"latencyTotal_mean\":0,\"propertyValue_circuitBreakerForceOpen\":false,\"propertyValue_circuitBreakerRequestVolumeThreshold\":20,\"propertyValue_circuitBreakerErrorThresholdPercentage\":50,\"propertyValue_executionIsolationStrategy\":\"THREAD\",\"rollingCountFallbackFailure\":0,\"isCircuitBreakerOpen\":false,\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\":20,\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\":1000,\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\":10000,\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\":10,\"latencyExecute\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"group\":\"IDENTITY\",\"latencyExecute_mean\":0,\"propertyValue_requestCacheEnabled\":true,\"rollingCountThreadPoolRejected\":0}\n\ndata: {\"rollingCountFailure\":0,\"propertyValue_executionIsolationThreadInterruptOnTimeout\":true,\"rollingCountTimeout\":0,\"rollingCountExceptionsThrown\":0,\"rollingCountFallbackSuccess\":0,\"errorCount\":0,\"type\":\"HystrixCommand\",\"propertyValue_circuitBreakerEnabled\":true,\"reportingHosts\":3,\"latencyTotal\":{\"0\":1,\"95\":1,\"99.5\":1,\"90\":1,\"25\":1,\"99\":1,\"75\":1,\"100\":1,\"50\":1},\"currentConcurrentExecutionCount\":0,\"rollingCountSemaphoreRejected\":0,\"rollingCountFallbackRejection\":0,\"rollingCountShortCircuited\":0,\"rollingCountResponsesFromCache\":0,\"propertyValue_circuitBreakerForceClosed\":false,\"name\":\"CryptexDecrypt\",\"propertyValue_executionIsolationThreadPoolKeyOverride\":\"null\",\"rollingCountSuccess\":1,\"propertyValue_requestLogEnabled\":true,\"requestCount\":1,\"rollingCountCollapsedRequests\":0,\"errorPercentage\":0,\"propertyValue_circuitBreakerSleepWindowInMilliseconds\":15000,\"latencyTotal_mean\":1,\"propertyValue_circuitBreakerForceOpen\":false,\"propertyValue_circuitBreakerRequestVolumeThreshold\":60,\"propertyValue_circuitBreakerErrorThresholdPercentage\":150,\"propertyValue_executionIsolationStrategy\":\"THREAD\",\"rollingCountFallbackFailure\":0,\"isCircuitBreakerOpen\":false,\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\":60,\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\":3000,\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\":30000,\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\":30,\"latencyExecute\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"group\":\"CRYPTEX\",\"latencyExecute_mean\":0,\"propertyValue_requestCacheEnabled\":true,\"rollingCountThreadPoolRejected\":0}\n```\n\n# Clojure Version\n\nA Clojure version of this module can be found at https://github.com/josephwilk/hystrix-event-stream-clj\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n\timplementation project(':hystrix-serialization')\n    compileOnly 'javax.servlet:servlet-api:2.5'\n    testImplementation 'javax.servlet:servlet-api:2.5'\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation 'org.mockito:mockito-all:1.9.5'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/metrics/eventstream/HystrixMetricsPoller.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.eventstream;\n\nimport com.fasterxml.jackson.core.JsonFactory;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.util.PlatformSpecific;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Polls Hystrix metrics and output JSON strings for each metric to a MetricsPollerListener.\n * <p>\n * Polling can be stopped/started. Use shutdown() to permanently shutdown the poller.\n *\n * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-metrics-event-stream,\n * the code below may reference a HystrixEventType that does not exist in hystrix-core.  If this happens,\n * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n * and we should log an error to get users to update their dependency set.\n *\n * @deprecated Prefer {@link com.netflix.hystrix.metric.consumer.HystrixDashboardStream}\n */\n@Deprecated //since 1.5.4\npublic class HystrixMetricsPoller {\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixMetricsPoller.class);\n    private final ScheduledExecutorService executor;\n    private final int delay;\n    private final AtomicBoolean running = new AtomicBoolean(false);\n    private volatile ScheduledFuture<?> scheduledTask = null;\n    private final MetricsAsJsonPollerListener listener;\n\n    /**\n     * Allocate resources to begin polling.\n     * <p>\n     * Use <code>start</code> to begin polling.\n     * <p>\n     * Use <code>shutdown</code> to cleanup resources and stop polling.\n     * <p>\n     * Use <code>pause</code> to temporarily stop polling that can be restarted again with <code>start</code>.\n     * \n     * @param listener for callbacks\n     * @param delay\n     */\n    public HystrixMetricsPoller(MetricsAsJsonPollerListener listener, int delay) {\n        this.listener = listener;\n\n        ThreadFactory threadFactory = null;\n        if (!PlatformSpecific.isAppEngineStandardEnvironment()) {\n            threadFactory = new MetricsPollerThreadFactory();\n        } else {\n            threadFactory = PlatformSpecific.getAppEngineThreadFactory();\n        }\n\n        executor = new ScheduledThreadPoolExecutor(1, threadFactory);\n        this.delay = delay;\n    }\n\n    /**\n     * Start polling.\n     */\n    public synchronized void start() {\n        // use compareAndSet to make sure it starts only once and when not running\n        if (running.compareAndSet(false, true)) {\n            logger.debug(\"Starting HystrixMetricsPoller\");\n            try {\n                scheduledTask = executor.scheduleWithFixedDelay(new MetricsPoller(listener), 0, delay, TimeUnit.MILLISECONDS);\n            } catch (Throwable ex) {\n                logger.error(\"Exception while creating the MetricsPoller task\");\n                ex.printStackTrace();\n                running.set(false);\n            }\n        }\n    }\n\n    /**\n     * Pause (stop) polling. Polling can be started again with <code>start</code> as long as <code>shutdown</code> is not called.\n     */\n    public synchronized void pause() {\n        // use compareAndSet to make sure it stops only once and when running\n        if (running.compareAndSet(true, false)) {\n            logger.debug(\"Stopping the HystrixMetricsPoller\");\n            scheduledTask.cancel(true);\n        } else {\n            logger.debug(\"Attempted to pause a stopped poller\");\n        }\n    }\n\n    /**\n     * Stops polling and shuts down the ExecutorService.\n     * <p>\n     * This instance can no longer be used after calling shutdown.\n     */\n    public synchronized void shutdown() {\n        pause();\n        executor.shutdown();\n    }\n\n    public boolean isRunning() {\n        return running.get();\n    }\n\n    /**\n     * Used to protect against leaking ExecutorServices and threads if this class is abandoned for GC without shutting down.\n     */\n    @SuppressWarnings(\"unused\")\n    private final Object finalizerGuardian = new Object() {\n        protected void finalize() throws Throwable {\n            if (!executor.isShutdown()) {\n                logger.warn(\"{} was not shutdown. Caught in Finalize Guardian and shutting down.\", HystrixMetricsPoller.class.getSimpleName());\n                try {\n                    shutdown();\n                } catch (Exception e) {\n                    logger.error(\"Failed to shutdown {}\", HystrixMetricsPoller.class.getSimpleName(), e);\n                }\n            }\n        };\n    };\n\n    public static interface MetricsAsJsonPollerListener {\n        public void handleJsonMetric(String json);\n    }\n\n    private class MetricsPoller implements Runnable {\n\n        private final MetricsAsJsonPollerListener listener;\n        private final JsonFactory jsonFactory = new JsonFactory();\n\n        public MetricsPoller(MetricsAsJsonPollerListener listener) {\n            this.listener = listener;\n        }\n\n        @Override\n        public void run() {\n            try {\n                for (HystrixCommandMetrics commandMetrics : HystrixCommandMetrics.getInstances()) {\n                    String jsonString = getCommandJson(commandMetrics);\n                    listener.handleJsonMetric(jsonString);\n                }\n\n                for (HystrixThreadPoolMetrics threadPoolMetrics : HystrixThreadPoolMetrics.getInstances()) {\n                    if (hasExecutedCommandsOnThread(threadPoolMetrics)) {\n                        String jsonString = getThreadPoolJson(threadPoolMetrics);\n                        listener.handleJsonMetric(jsonString);\n                    }\n                }\n\n                for (HystrixCollapserMetrics collapserMetrics : HystrixCollapserMetrics.getInstances()) {\n                    String jsonString = getCollapserJson(collapserMetrics);\n                    listener.handleJsonMetric(jsonString);\n                }\n\n            } catch (Exception e) {\n                logger.warn(\"Failed to output metrics as JSON\", e);\n                // shutdown\n                pause();\n                return;\n            }\n        }\n\n        private void safelyWriteNumberField(JsonGenerator json, String name, Func0<Long> metricGenerator) throws IOException {\n            try {\n                json.writeNumberField(name, metricGenerator.call());\n            } catch (NoSuchFieldError error) {\n                logger.error(\"While publishing Hystrix metrics stream, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                json.writeNumberField(name, 0L);\n            }\n        }\n\n        private String getCommandJson(final HystrixCommandMetrics commandMetrics) throws IOException {\n            HystrixCommandKey key = commandMetrics.getCommandKey();\n            HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);\n\n            StringWriter jsonString = new StringWriter();\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n            json.writeStartObject();\n            json.writeStringField(\"type\", \"HystrixCommand\");\n            json.writeStringField(\"name\", key.name());\n            json.writeStringField(\"group\", commandMetrics.getCommandGroup().name());\n            json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n            // circuit breaker\n            if (circuitBreaker == null) {\n                // circuit breaker is disabled and thus never open\n                json.writeBooleanField(\"isCircuitBreakerOpen\", false);\n            } else {\n                json.writeBooleanField(\"isCircuitBreakerOpen\", circuitBreaker.isOpen());\n            }\n            HealthCounts healthCounts = commandMetrics.getHealthCounts();\n            json.writeNumberField(\"errorPercentage\", healthCounts.getErrorPercentage());\n            json.writeNumberField(\"errorCount\", healthCounts.getErrorCount());\n            json.writeNumberField(\"requestCount\", healthCounts.getTotalRequests());\n\n            // rolling counters\n            safelyWriteNumberField(json, \"rollingCountBadRequests\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.BAD_REQUEST);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountCollapsedRequests\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.COLLAPSED);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountEmit\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.EMIT);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountExceptionsThrown\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.EXCEPTION_THROWN);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFailure\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FAILURE);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFallbackEmit\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_EMIT);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFallbackFailure\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_FAILURE);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFallbackMissing\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_MISSING);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFallbackRejection\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_REJECTION);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountFallbackSuccess\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_SUCCESS);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountResponsesFromCache\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.RESPONSE_FROM_CACHE);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountSemaphoreRejected\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.SEMAPHORE_REJECTED);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountShortCircuited\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.SHORT_CIRCUITED);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountSuccess\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.SUCCESS);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountThreadPoolRejected\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.THREAD_POOL_REJECTED);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountTimeout\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return commandMetrics.getRollingCount(HystrixEventType.TIMEOUT);\n                }\n            });\n\n            json.writeNumberField(\"currentConcurrentExecutionCount\", commandMetrics.getCurrentConcurrentExecutionCount());\n            json.writeNumberField(\"rollingMaxConcurrentExecutionCount\", commandMetrics.getRollingMaxConcurrentExecutions());\n\n            // latency percentiles\n            json.writeNumberField(\"latencyExecute_mean\", commandMetrics.getExecutionTimeMean());\n            json.writeObjectFieldStart(\"latencyExecute\");\n            json.writeNumberField(\"0\", commandMetrics.getExecutionTimePercentile(0));\n            json.writeNumberField(\"25\", commandMetrics.getExecutionTimePercentile(25));\n            json.writeNumberField(\"50\", commandMetrics.getExecutionTimePercentile(50));\n            json.writeNumberField(\"75\", commandMetrics.getExecutionTimePercentile(75));\n            json.writeNumberField(\"90\", commandMetrics.getExecutionTimePercentile(90));\n            json.writeNumberField(\"95\", commandMetrics.getExecutionTimePercentile(95));\n            json.writeNumberField(\"99\", commandMetrics.getExecutionTimePercentile(99));\n            json.writeNumberField(\"99.5\", commandMetrics.getExecutionTimePercentile(99.5));\n            json.writeNumberField(\"100\", commandMetrics.getExecutionTimePercentile(100));\n            json.writeEndObject();\n            //\n            json.writeNumberField(\"latencyTotal_mean\", commandMetrics.getTotalTimeMean());\n            json.writeObjectFieldStart(\"latencyTotal\");\n            json.writeNumberField(\"0\", commandMetrics.getTotalTimePercentile(0));\n            json.writeNumberField(\"25\", commandMetrics.getTotalTimePercentile(25));\n            json.writeNumberField(\"50\", commandMetrics.getTotalTimePercentile(50));\n            json.writeNumberField(\"75\", commandMetrics.getTotalTimePercentile(75));\n            json.writeNumberField(\"90\", commandMetrics.getTotalTimePercentile(90));\n            json.writeNumberField(\"95\", commandMetrics.getTotalTimePercentile(95));\n            json.writeNumberField(\"99\", commandMetrics.getTotalTimePercentile(99));\n            json.writeNumberField(\"99.5\", commandMetrics.getTotalTimePercentile(99.5));\n            json.writeNumberField(\"100\", commandMetrics.getTotalTimePercentile(100));\n            json.writeEndObject();\n\n            // property values for reporting what is actually seen by the command rather than what was set somewhere\n            HystrixCommandProperties commandProperties = commandMetrics.getProperties();\n\n            json.writeNumberField(\"propertyValue_circuitBreakerRequestVolumeThreshold\", commandProperties.circuitBreakerRequestVolumeThreshold().get());\n            json.writeNumberField(\"propertyValue_circuitBreakerSleepWindowInMilliseconds\", commandProperties.circuitBreakerSleepWindowInMilliseconds().get());\n            json.writeNumberField(\"propertyValue_circuitBreakerErrorThresholdPercentage\", commandProperties.circuitBreakerErrorThresholdPercentage().get());\n            json.writeBooleanField(\"propertyValue_circuitBreakerForceOpen\", commandProperties.circuitBreakerForceOpen().get());\n            json.writeBooleanField(\"propertyValue_circuitBreakerForceClosed\", commandProperties.circuitBreakerForceClosed().get());\n            json.writeBooleanField(\"propertyValue_circuitBreakerEnabled\", commandProperties.circuitBreakerEnabled().get());\n\n            json.writeStringField(\"propertyValue_executionIsolationStrategy\", commandProperties.executionIsolationStrategy().get().name());\n            json.writeNumberField(\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\", commandProperties.executionTimeoutInMilliseconds().get());\n            json.writeNumberField(\"propertyValue_executionTimeoutInMilliseconds\", commandProperties.executionTimeoutInMilliseconds().get());\n            json.writeBooleanField(\"propertyValue_executionIsolationThreadInterruptOnTimeout\", commandProperties.executionIsolationThreadInterruptOnTimeout().get());\n            json.writeStringField(\"propertyValue_executionIsolationThreadPoolKeyOverride\", commandProperties.executionIsolationThreadPoolKeyOverride().get());\n            json.writeNumberField(\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\", commandProperties.executionIsolationSemaphoreMaxConcurrentRequests().get());\n            json.writeNumberField(\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\", commandProperties.fallbackIsolationSemaphoreMaxConcurrentRequests().get());\n\n                    /*\n                     * The following are commented out as these rarely change and are verbose for streaming for something people don't change.\n                     * We could perhaps allow a property or request argument to include these.\n                     */\n\n            //                    json.put(\"propertyValue_metricsRollingPercentileEnabled\", commandProperties.metricsRollingPercentileEnabled().get());\n            //                    json.put(\"propertyValue_metricsRollingPercentileBucketSize\", commandProperties.metricsRollingPercentileBucketSize().get());\n            //                    json.put(\"propertyValue_metricsRollingPercentileWindow\", commandProperties.metricsRollingPercentileWindowInMilliseconds().get());\n            //                    json.put(\"propertyValue_metricsRollingPercentileWindowBuckets\", commandProperties.metricsRollingPercentileWindowBuckets().get());\n            //                    json.put(\"propertyValue_metricsRollingStatisticalWindowBuckets\", commandProperties.metricsRollingStatisticalWindowBuckets().get());\n            json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", commandProperties.metricsRollingStatisticalWindowInMilliseconds().get());\n\n            json.writeBooleanField(\"propertyValue_requestCacheEnabled\", commandProperties.requestCacheEnabled().get());\n            json.writeBooleanField(\"propertyValue_requestLogEnabled\", commandProperties.requestLogEnabled().get());\n\n            json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n            json.writeStringField(\"threadPool\", commandMetrics.getThreadPoolKey().name());\n\n            json.writeEndObject();\n            json.close();\n\n            return jsonString.getBuffer().toString();\n        }\n\n        private boolean hasExecutedCommandsOnThread(HystrixThreadPoolMetrics threadPoolMetrics) {\n            return threadPoolMetrics.getCurrentCompletedTaskCount().intValue() > 0;\n        }\n\n        private String getThreadPoolJson(final HystrixThreadPoolMetrics threadPoolMetrics) throws IOException {\n            HystrixThreadPoolKey key = threadPoolMetrics.getThreadPoolKey();\n            StringWriter jsonString = new StringWriter();\n            JsonGenerator json = jsonFactory.createJsonGenerator(jsonString);\n            json.writeStartObject();\n\n            json.writeStringField(\"type\", \"HystrixThreadPool\");\n            json.writeStringField(\"name\", key.name());\n            json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n            json.writeNumberField(\"currentActiveCount\", threadPoolMetrics.getCurrentActiveCount().intValue());\n            json.writeNumberField(\"currentCompletedTaskCount\", threadPoolMetrics.getCurrentCompletedTaskCount().longValue());\n            json.writeNumberField(\"currentCorePoolSize\", threadPoolMetrics.getCurrentCorePoolSize().intValue());\n            json.writeNumberField(\"currentLargestPoolSize\", threadPoolMetrics.getCurrentLargestPoolSize().intValue());\n            json.writeNumberField(\"currentMaximumPoolSize\", threadPoolMetrics.getCurrentMaximumPoolSize().intValue());\n            json.writeNumberField(\"currentPoolSize\", threadPoolMetrics.getCurrentPoolSize().intValue());\n            json.writeNumberField(\"currentQueueSize\", threadPoolMetrics.getCurrentQueueSize().intValue());\n            json.writeNumberField(\"currentTaskCount\", threadPoolMetrics.getCurrentTaskCount().longValue());\n            safelyWriteNumberField(json, \"rollingCountThreadsExecuted\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return threadPoolMetrics.getRollingCount(HystrixEventType.ThreadPool.EXECUTED);\n                }\n            });\n            json.writeNumberField(\"rollingMaxActiveThreads\", threadPoolMetrics.getRollingMaxActiveThreads());\n            safelyWriteNumberField(json, \"rollingCountCommandRejections\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return threadPoolMetrics.getRollingCount(HystrixEventType.ThreadPool.REJECTED);\n                }\n            });\n\n            json.writeNumberField(\"propertyValue_queueSizeRejectionThreshold\", threadPoolMetrics.getProperties().queueSizeRejectionThreshold().get());\n            json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", threadPoolMetrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get());\n\n            json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n\n            json.writeEndObject();\n            json.close();\n\n            return jsonString.getBuffer().toString();\n        }\n\n        private String getCollapserJson(final HystrixCollapserMetrics collapserMetrics) throws IOException {\n            HystrixCollapserKey key = collapserMetrics.getCollapserKey();\n            StringWriter jsonString = new StringWriter();\n            JsonGenerator json = jsonFactory.createJsonGenerator(jsonString);\n            json.writeStartObject();\n\n            json.writeStringField(\"type\", \"HystrixCollapser\");\n            json.writeStringField(\"name\", key.name());\n            json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n            safelyWriteNumberField(json, \"rollingCountRequestsBatched\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return collapserMetrics.getRollingCount(HystrixEventType.Collapser.ADDED_TO_BATCH);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountBatches\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return collapserMetrics.getRollingCount(HystrixEventType.Collapser.BATCH_EXECUTED);\n                }\n            });\n            safelyWriteNumberField(json, \"rollingCountResponsesFromCache\", new Func0<Long>() {\n                @Override\n                public Long call() {\n                    return collapserMetrics.getRollingCount(HystrixEventType.Collapser.RESPONSE_FROM_CACHE);\n                }\n            });\n\n            // batch size percentiles\n            json.writeNumberField(\"batchSize_mean\", collapserMetrics.getBatchSizeMean());\n            json.writeObjectFieldStart(\"batchSize\");\n            json.writeNumberField(\"25\", collapserMetrics.getBatchSizePercentile(25));\n            json.writeNumberField(\"50\", collapserMetrics.getBatchSizePercentile(50));\n            json.writeNumberField(\"75\", collapserMetrics.getBatchSizePercentile(75));\n            json.writeNumberField(\"90\", collapserMetrics.getBatchSizePercentile(90));\n            json.writeNumberField(\"95\", collapserMetrics.getBatchSizePercentile(95));\n            json.writeNumberField(\"99\", collapserMetrics.getBatchSizePercentile(99));\n            json.writeNumberField(\"99.5\", collapserMetrics.getBatchSizePercentile(99.5));\n            json.writeNumberField(\"100\", collapserMetrics.getBatchSizePercentile(100));\n            json.writeEndObject();\n\n            // shard size percentiles (commented-out for now)\n            //json.writeNumberField(\"shardSize_mean\", collapserMetrics.getShardSizeMean());\n            //json.writeObjectFieldStart(\"shardSize\");\n            //json.writeNumberField(\"25\", collapserMetrics.getShardSizePercentile(25));\n            //json.writeNumberField(\"50\", collapserMetrics.getShardSizePercentile(50));\n            //json.writeNumberField(\"75\", collapserMetrics.getShardSizePercentile(75));\n            //json.writeNumberField(\"90\", collapserMetrics.getShardSizePercentile(90));\n            //json.writeNumberField(\"95\", collapserMetrics.getShardSizePercentile(95));\n            //json.writeNumberField(\"99\", collapserMetrics.getShardSizePercentile(99));\n            //json.writeNumberField(\"99.5\", collapserMetrics.getShardSizePercentile(99.5));\n            //json.writeNumberField(\"100\", collapserMetrics.getShardSizePercentile(100));\n            //json.writeEndObject();\n\n            //json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", collapserMetrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get());\n            json.writeBooleanField(\"propertyValue_requestCacheEnabled\", collapserMetrics.getProperties().requestCacheEnabled().get());\n            json.writeNumberField(\"propertyValue_maxRequestsInBatch\", collapserMetrics.getProperties().maxRequestsInBatch().get());\n            json.writeNumberField(\"propertyValue_timerDelayInMilliseconds\", collapserMetrics.getProperties().timerDelayInMilliseconds().get());\n\n            json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n\n            json.writeEndObject();\n            json.close();\n\n            return jsonString.getBuffer().toString();\n        }\n    }\n\n    private static class MetricsPollerThreadFactory implements ThreadFactory {\n        private static final String MetricsThreadName = \"HystrixMetricPoller\";\n\n        private final ThreadFactory defaultFactory = Executors.defaultThreadFactory();\n\n        public Thread newThread(Runnable r) {\n            Thread thread = defaultFactory.newThread(r);\n            thread.setName(MetricsThreadName);\n            thread.setDaemon(true);\n            return thread;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/metrics/eventstream/HystrixMetricsStreamServlet.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.eventstream;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.contrib.sample.stream.HystrixSampleSseServlet;\nimport com.netflix.hystrix.metric.consumer.HystrixDashboardStream;\nimport com.netflix.hystrix.serial.SerialHystrixDashboardData;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Streams Hystrix metrics in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-*.jar in your classpath.\n * <p>\n * 2) Adding the following to web.xml:\n * <pre>{@code\n * <servlet>\n *  <description></description>\n *  <display-name>HystrixMetricsStreamServlet</display-name>\n *  <servlet-name>HystrixMetricsStreamServlet</servlet-name>\n *  <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>\n * </servlet>\n * <servlet-mapping>\n *  <servlet-name>HystrixMetricsStreamServlet</servlet-name>\n *  <url-pattern>/hystrix.stream</url-pattern>\n * </servlet-mapping>\n * } </pre>\n */\npublic class HystrixMetricsStreamServlet extends HystrixSampleSseServlet {\n\n    private static final long serialVersionUID = -7548505095303313237L;\n\n    /* used to track number of connections and throttle */\n    private static AtomicInteger concurrentConnections = new AtomicInteger(0);\n    private static DynamicIntProperty maxConcurrentConnections =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n    public HystrixMetricsStreamServlet() {\n        this(HystrixDashboardStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n    }\n\n    /* package-private */ HystrixMetricsStreamServlet(Observable<HystrixDashboardStream.DashboardData> sampleStream, int pausePollerThreadDelayInMs) {\n        super(sampleStream.concatMap(new Func1<HystrixDashboardStream.DashboardData, Observable<String>>() {\n            @Override\n            public Observable<String> call(HystrixDashboardStream.DashboardData dashboardData) {\n                return Observable.from(SerialHystrixDashboardData.toMultipleJsonStrings(dashboardData));\n            }\n        }), pausePollerThreadDelayInMs);\n    }\n\n    @Override\n    protected int getMaxNumberConcurrentConnectionsAllowed() {\n        return maxConcurrentConnections.get();\n    }\n\n    @Override\n    protected int getNumberCurrentConnections() {\n        return concurrentConnections.get();\n    }\n\n    @Override\n    protected int incrementAndGetCurrentConcurrentConnections() {\n        return concurrentConnections.incrementAndGet();\n    }\n\n    @Override\n    protected void decrementCurrentConcurrentConnections() {\n        concurrentConnections.decrementAndGet();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/requests/stream/HystrixRequestEventsJsonStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.requests.stream;\n\nimport com.fasterxml.jackson.core.JsonFactory;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixRequestEvents;\nimport com.netflix.hystrix.metric.HystrixRequestEventsStream;\nimport rx.Observable;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Stream that converts HystrixRequestEvents into JSON.  This isn't needed anymore, as it more straightforward\n * to consider serialization completely separately from the domain object stream\n *\n * @deprecated Instead, prefer mapping your preferred serialization on top of {@link HystrixRequestEventsStream#observe()}.\n */\n@Deprecated //since 1.5.4\npublic class HystrixRequestEventsJsonStream {\n    private static final JsonFactory jsonFactory = new JsonFactory();\n\n    public Observable<HystrixRequestEvents> getStream() {\n        return HystrixRequestEventsStream.getInstance()\n                .observe();\n    }\n\n    public static String convertRequestsToJson(Collection<HystrixRequestEvents> requests) throws IOException {\n        StringWriter jsonString = new StringWriter();\n        JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n        json.writeStartArray();\n        for (HystrixRequestEvents request : requests) {\n            writeRequestAsJson(json, request);\n        }\n        json.writeEndArray();\n        json.close();\n        return jsonString.getBuffer().toString();\n    }\n\n    public static String convertRequestToJson(HystrixRequestEvents request) throws IOException {\n        StringWriter jsonString = new StringWriter();\n        JsonGenerator json = jsonFactory.createGenerator(jsonString);\n        writeRequestAsJson(json, request);\n        json.close();\n        return jsonString.getBuffer().toString();\n    }\n\n\n    private static void writeRequestAsJson(JsonGenerator json, HystrixRequestEvents request) throws IOException {\n        json.writeStartArray();\n\n        for (Map.Entry<HystrixRequestEvents.ExecutionSignature, List<Integer>> entry: request.getExecutionsMappedToLatencies().entrySet()) {\n            convertExecutionToJson(json, entry.getKey(), entry.getValue());\n        }\n\n        json.writeEndArray();\n    }\n\n    private static void convertExecutionToJson(JsonGenerator json, HystrixRequestEvents.ExecutionSignature executionSignature, List<Integer> latencies) throws IOException {\n        json.writeStartObject();\n        json.writeStringField(\"name\", executionSignature.getCommandName());\n        json.writeArrayFieldStart(\"events\");\n        ExecutionResult.EventCounts eventCounts = executionSignature.getEventCounts();\n        for (HystrixEventType eventType: HystrixEventType.values()) {\n            if (eventType != HystrixEventType.COLLAPSED) {\n                if (eventCounts.contains(eventType)) {\n                    int eventCount = eventCounts.getCount(eventType);\n                    if (eventCount > 1) {\n                        json.writeStartObject();\n                        json.writeStringField(\"name\", eventType.name());\n                        json.writeNumberField(\"count\", eventCount);\n                        json.writeEndObject();\n                    } else {\n                        json.writeString(eventType.name());\n                    }\n                }\n            }\n        }\n        json.writeEndArray();\n        json.writeArrayFieldStart(\"latencies\");\n        for (int latency: latencies) {\n            json.writeNumber(latency);\n        }\n        json.writeEndArray();\n        if (executionSignature.getCachedCount() > 0) {\n            json.writeNumberField(\"cached\", executionSignature.getCachedCount());\n        }\n        if (executionSignature.getEventCounts().contains(HystrixEventType.COLLAPSED)) {\n            json.writeObjectFieldStart(\"collapsed\");\n            json.writeStringField(\"name\", executionSignature.getCollapserKey().name());\n            json.writeNumberField(\"count\", executionSignature.getCollapserBatchSize());\n            json.writeEndObject();\n        }\n        json.writeEndObject();\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/requests/stream/HystrixRequestEventsSseServlet.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.requests.stream;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.contrib.sample.stream.HystrixSampleSseServlet;\nimport com.netflix.hystrix.metric.HystrixRequestEvents;\nimport com.netflix.hystrix.metric.HystrixRequestEventsStream;\nimport com.netflix.hystrix.serial.SerialHystrixRequestEvents;\nimport rx.Observable;\nimport rx.functions.Func1;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Servlet that writes SSE JSON every time a request is made\n */\npublic class HystrixRequestEventsSseServlet extends HystrixSampleSseServlet {\n\n    private static final long serialVersionUID = 6389353893099737870L;\n\n    /* used to track number of connections and throttle */\n    private static AtomicInteger concurrentConnections = new AtomicInteger(0);\n    private static DynamicIntProperty maxConcurrentConnections =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n    public HystrixRequestEventsSseServlet() {\n        this(HystrixRequestEventsStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n    }\n\n    /* package-private */ HystrixRequestEventsSseServlet(Observable<HystrixRequestEvents> sampleStream, int pausePollerThreadDelayInMs) {\n        super(sampleStream.map(new Func1<HystrixRequestEvents, String>() {\n            @Override\n            public String call(HystrixRequestEvents requestEvents) {\n                return SerialHystrixRequestEvents.toJsonString(requestEvents);\n            }\n        }), pausePollerThreadDelayInMs);\n    }\n\n    @Override\n    protected int getMaxNumberConcurrentConnectionsAllowed() {\n        return maxConcurrentConnections.get();\n    }\n\n    @Override\n    protected int getNumberCurrentConnections() {\n        return concurrentConnections.get();\n    }\n\n    @Override\n    protected int incrementAndGetCurrentConcurrentConnections() {\n        return concurrentConnections.incrementAndGet();\n    }\n\n    @Override\n    protected void decrementCurrentConcurrentConnections() {\n        concurrentConnections.decrementAndGet();\n    }\n}\n\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigSseServlet.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixConfigurationStream;\nimport com.netflix.hystrix.serial.SerialHystrixConfiguration;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Streams Hystrix config in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-*.jar in your classpath.\n * <p>\n * 2) Adding the following to web.xml:\n * <pre>{@code\n * <servlet>\n *  <description></description>\n *  <display-name>HystrixConfigSseServlet</display-name>\n *  <servlet-name>HystrixConfigSseServlet</servlet-name>\n *  <servlet-class>com.netflix.hystrix.contrib.sample.stream.HystrixConfigSseServlet</servlet-class>\n * </servlet>\n * <servlet-mapping>\n *  <servlet-name>HystrixConfigSseServlet</servlet-name>\n *  <url-pattern>/hystrix/config.stream</url-pattern>\n * </servlet-mapping>\n * } </pre>\n */\npublic class HystrixConfigSseServlet extends HystrixSampleSseServlet {\n\n    private static final long serialVersionUID = -3599771169762858235L;\n\n    /* used to track number of connections and throttle */\n    private static AtomicInteger concurrentConnections = new AtomicInteger(0);\n    private static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n    public HystrixConfigSseServlet() {\n        this(HystrixConfigurationStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n    }\n\n    /* package-private */ HystrixConfigSseServlet(Observable<HystrixConfiguration> sampleStream, int pausePollerThreadDelayInMs) {\n        super(sampleStream.map(new Func1<HystrixConfiguration, String>() {\n            @Override\n            public String call(HystrixConfiguration hystrixConfiguration) {\n                return SerialHystrixConfiguration.toJsonString(hystrixConfiguration);\n            }\n        }), pausePollerThreadDelayInMs);\n    }\n\n    @Override\n    protected int getMaxNumberConcurrentConnectionsAllowed() {\n        return maxConcurrentConnections.get();\n    }\n\n    @Override\n    protected int getNumberCurrentConnections() {\n        return concurrentConnections.get();\n    }\n\n    @Override\n    protected int incrementAndGetCurrentConcurrentConnections() {\n        return concurrentConnections.incrementAndGet();\n    }\n\n    @Override\n    protected void decrementCurrentConcurrentConnections() {\n        concurrentConnections.decrementAndGet();\n    }\n}\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigurationJsonStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.fasterxml.jackson.core.JsonFactory;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.config.HystrixCollapserConfiguration;\nimport com.netflix.hystrix.config.HystrixCommandConfiguration;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixConfigurationStream;\nimport com.netflix.hystrix.config.HystrixThreadPoolConfiguration;\nimport com.netflix.hystrix.metric.HystrixRequestEventsStream;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.Map;\n\n/**\n * Links HystrixConfigurationStream and JSON encoding.  This may be consumed in a variety of ways:\n * -such as-\n * <ul>\n * <li> {@link HystrixConfigSseServlet} for mapping a specific URL to this data as an SSE stream\n * <li> Consumer of your choice that wants control over where to embed this stream\n * </ul>\n *\n * @deprecated Instead, prefer mapping your preferred serialization on top of {@link HystrixConfigurationStream#observe()}.\n */\n@Deprecated //since 1.5.4\npublic class HystrixConfigurationJsonStream {\n\n    private static final JsonFactory jsonFactory = new JsonFactory();\n    private final Func1<Integer, Observable<HystrixConfiguration>> streamGenerator;\n\n    @Deprecated //since 1.5.4\n    public HystrixConfigurationJsonStream() {\n        this.streamGenerator = new Func1<Integer, Observable<HystrixConfiguration>>() {\n            @Override\n            public Observable<HystrixConfiguration> call(Integer delay) {\n                return HystrixConfigurationStream.getInstance().observe();\n            }\n        };\n    }\n\n    @Deprecated //since 1.5.4\n    public HystrixConfigurationJsonStream(Func1<Integer, Observable<HystrixConfiguration>> streamGenerator) {\n        this.streamGenerator = streamGenerator;\n    }\n\n    private static final Func1<HystrixConfiguration, String> convertToJson = new Func1<HystrixConfiguration, String>() {\n        @Override\n        public String call(HystrixConfiguration hystrixConfiguration) {\n            try {\n                return convertToString(hystrixConfiguration);\n            } catch (IOException ioe) {\n                throw new RuntimeException(ioe);\n            }\n        }\n    };\n\n    private static void writeCommandConfigJson(JsonGenerator json, HystrixCommandKey key, HystrixCommandConfiguration commandConfig) throws IOException {\n        json.writeObjectFieldStart(key.name());\n        json.writeStringField(\"threadPoolKey\", commandConfig.getThreadPoolKey().name());\n        json.writeStringField(\"groupKey\", commandConfig.getGroupKey().name());\n        json.writeObjectFieldStart(\"execution\");\n        HystrixCommandConfiguration.HystrixCommandExecutionConfig executionConfig = commandConfig.getExecutionConfig();\n        json.writeStringField(\"isolationStrategy\", executionConfig.getIsolationStrategy().name());\n        json.writeStringField(\"threadPoolKeyOverride\", executionConfig.getThreadPoolKeyOverride());\n        json.writeBooleanField(\"requestCacheEnabled\", executionConfig.isRequestCacheEnabled());\n        json.writeBooleanField(\"requestLogEnabled\", executionConfig.isRequestLogEnabled());\n        json.writeBooleanField(\"timeoutEnabled\", executionConfig.isTimeoutEnabled());\n        json.writeBooleanField(\"fallbackEnabled\", executionConfig.isFallbackEnabled());\n        json.writeNumberField(\"timeoutInMilliseconds\", executionConfig.getTimeoutInMilliseconds());\n        json.writeNumberField(\"semaphoreSize\", executionConfig.getSemaphoreMaxConcurrentRequests());\n        json.writeNumberField(\"fallbackSemaphoreSize\", executionConfig.getFallbackMaxConcurrentRequest());\n        json.writeBooleanField(\"threadInterruptOnTimeout\", executionConfig.isThreadInterruptOnTimeout());\n        json.writeEndObject();\n        json.writeObjectFieldStart(\"metrics\");\n        HystrixCommandConfiguration.HystrixCommandMetricsConfig metricsConfig = commandConfig.getMetricsConfig();\n        json.writeNumberField(\"healthBucketSizeInMs\", metricsConfig.getHealthIntervalInMilliseconds());\n        json.writeNumberField(\"percentileBucketSizeInMilliseconds\", metricsConfig.getRollingPercentileBucketSizeInMilliseconds());\n        json.writeNumberField(\"percentileBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeBooleanField(\"percentileEnabled\", metricsConfig.isRollingPercentileEnabled());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", metricsConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n        json.writeObjectFieldStart(\"circuitBreaker\");\n        HystrixCommandConfiguration.HystrixCommandCircuitBreakerConfig circuitBreakerConfig = commandConfig.getCircuitBreakerConfig();\n        json.writeBooleanField(\"enabled\", circuitBreakerConfig.isEnabled());\n        json.writeBooleanField(\"isForcedOpen\", circuitBreakerConfig.isForceOpen());\n        json.writeBooleanField(\"isForcedClosed\", circuitBreakerConfig.isForceOpen());\n        json.writeNumberField(\"requestVolumeThreshold\", circuitBreakerConfig.getRequestVolumeThreshold());\n        json.writeNumberField(\"errorPercentageThreshold\", circuitBreakerConfig.getErrorThresholdPercentage());\n        json.writeNumberField(\"sleepInMilliseconds\", circuitBreakerConfig.getSleepWindowInMilliseconds());\n        json.writeEndObject();\n        json.writeEndObject();\n    }\n\n    private static void writeThreadPoolConfigJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolConfiguration threadPoolConfig) throws IOException {\n        json.writeObjectFieldStart(threadPoolKey.name());\n        json.writeNumberField(\"coreSize\", threadPoolConfig.getCoreSize());\n        json.writeNumberField(\"maximumSize\", threadPoolConfig.getMaximumSize());\n        json.writeNumberField(\"actualMaximumSize\", threadPoolConfig.getActualMaximumSize());\n        json.writeNumberField(\"maxQueueSize\", threadPoolConfig.getMaxQueueSize());\n        json.writeNumberField(\"queueRejectionThreshold\", threadPoolConfig.getQueueRejectionThreshold());\n        json.writeNumberField(\"keepAliveTimeInMinutes\", threadPoolConfig.getKeepAliveTimeInMinutes());\n        json.writeBooleanField(\"allowMaximumSizeToDivergeFromCoreSize\", threadPoolConfig.getAllowMaximumSizeToDivergeFromCoreSize());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", threadPoolConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", threadPoolConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n    }\n\n    private static void writeCollapserConfigJson(JsonGenerator json, HystrixCollapserKey collapserKey, HystrixCollapserConfiguration collapserConfig) throws IOException {\n        json.writeObjectFieldStart(collapserKey.name());\n        json.writeNumberField(\"maxRequestsInBatch\", collapserConfig.getMaxRequestsInBatch());\n        json.writeNumberField(\"timerDelayInMilliseconds\", collapserConfig.getTimerDelayInMilliseconds());\n        json.writeBooleanField(\"requestCacheEnabled\", collapserConfig.isRequestCacheEnabled());\n        json.writeObjectFieldStart(\"metrics\");\n        HystrixCollapserConfiguration.CollapserMetricsConfig metricsConfig = collapserConfig.getCollapserMetricsConfig();\n        json.writeNumberField(\"percentileBucketSizeInMilliseconds\", metricsConfig.getRollingPercentileBucketSizeInMilliseconds());\n        json.writeNumberField(\"percentileBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeBooleanField(\"percentileEnabled\", metricsConfig.isRollingPercentileEnabled());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", metricsConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n        json.writeEndObject();\n    }\n\n   public static String convertToString(HystrixConfiguration config) throws IOException {\n        StringWriter jsonString = new StringWriter();\n        JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n        json.writeStartObject();\n        json.writeStringField(\"type\", \"HystrixConfig\");\n        json.writeObjectFieldStart(\"commands\");\n        for (Map.Entry<HystrixCommandKey, HystrixCommandConfiguration> entry: config.getCommandConfig().entrySet()) {\n            final HystrixCommandKey key = entry.getKey();\n            final HystrixCommandConfiguration commandConfig = entry.getValue();\n            writeCommandConfigJson(json, key, commandConfig);\n\n        }\n        json.writeEndObject();\n\n        json.writeObjectFieldStart(\"threadpools\");\n        for (Map.Entry<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> entry: config.getThreadPoolConfig().entrySet()) {\n            final HystrixThreadPoolKey threadPoolKey = entry.getKey();\n            final HystrixThreadPoolConfiguration threadPoolConfig = entry.getValue();\n            writeThreadPoolConfigJson(json, threadPoolKey, threadPoolConfig);\n        }\n        json.writeEndObject();\n\n        json.writeObjectFieldStart(\"collapsers\");\n        for (Map.Entry<HystrixCollapserKey, HystrixCollapserConfiguration> entry: config.getCollapserConfig().entrySet()) {\n            final HystrixCollapserKey collapserKey = entry.getKey();\n            final HystrixCollapserConfiguration collapserConfig = entry.getValue();\n            writeCollapserConfigJson(json, collapserKey, collapserConfig);\n        }\n        json.writeEndObject();\n        json.writeEndObject();\n        json.close();\n\n        return jsonString.getBuffer().toString();\n    }\n\n    /**\n     * @deprecated Not for public use.  Using the delay param prevents streams from being efficiently shared.\n     * Please use {@link HystrixConfigurationStream#observe()}\n     * @param delay interval between data emissions\n     * @return sampled utilization as Java object, taken on a timer\n     */\n    @Deprecated //deprecated in 1.5.4\n    public Observable<HystrixConfiguration> observe(int delay) {\n        return streamGenerator.call(delay);\n    }\n\n    /**\n     * @deprecated Not for public use.  Using the delay param prevents streams from being efficiently shared.\n     * Please use {@link HystrixConfigurationStream#observe()}\n     * and you can map to JSON string via {@link HystrixConfigurationJsonStream#convertToString(HystrixConfiguration)}\n     * @param delay interval between data emissions\n     * @return sampled utilization as JSON string, taken on a timer\n     */\n    @Deprecated //deprecated in 1.5.4\n    public Observable<String> observeJson(int delay) {\n        return streamGenerator.call(delay).map(convertToJson);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixSampleSseServlet.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.schedulers.Schedulers;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n */\npublic abstract class HystrixSampleSseServlet extends HttpServlet {\n    protected final Observable<String> sampleStream;\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixSampleSseServlet.class);\n\n    //wake up occasionally and check that poller is still alive.  this value controls how often\n    protected static final int DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS = 500;\n\n    private final int pausePollerThreadDelayInMs;\n\n    /* response is not thread-safe */\n    private final Object responseWriteLock = new Object();\n\n    /* Set to true upon shutdown, so it's OK to be shared among all SampleSseServlets */\n    private static volatile boolean isDestroyed = false;\n\n    protected HystrixSampleSseServlet(Observable<String> sampleStream) {\n        this.sampleStream = sampleStream;\n        this.pausePollerThreadDelayInMs = DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS;\n    }\n\n    protected HystrixSampleSseServlet(Observable<String> sampleStream, int pausePollerThreadDelayInMs) {\n        this.sampleStream = sampleStream;\n        this.pausePollerThreadDelayInMs = pausePollerThreadDelayInMs;\n    }\n\n    protected abstract int getMaxNumberConcurrentConnectionsAllowed();\n\n    protected abstract int getNumberCurrentConnections();\n\n    protected abstract int incrementAndGetCurrentConcurrentConnections();\n\n    protected abstract void decrementCurrentConcurrentConnections();\n\n    /**\n     * Handle incoming GETs\n     */\n    @Override\n    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n        if (isDestroyed) {\n            response.sendError(503, \"Service has been shut down.\");\n        } else {\n            handleRequest(request, response);\n        }\n    }\n\n    /**\n     * WebSphere won't shutdown a servlet until after a 60 second timeout if there is an instance of the servlet executing\n     * a request.  Add this method to enable a hook to notify Hystrix to shutdown.  You must invoke this method at\n     * shutdown, perhaps from some other servlet's destroy() method.\n     */\n    public static void shutdown() {\n        isDestroyed = true;\n    }\n\n    @Override\n    public void init() throws ServletException {\n        isDestroyed = false;\n    }\n\n    /**\n     * Handle servlet being undeployed by gracefully releasing connections so poller threads stop.\n     */\n    @Override\n    public void destroy() {\n        /* set marker so the loops can break out */\n        isDestroyed = true;\n        super.destroy();\n    }\n\n    /**\n     * - maintain an open connection with the client\n     * - on initial connection send latest data of each requested event type\n     * - subsequently send all changes for each requested event type\n     *\n     * @param request  incoming HTTP Request\n     * @param response outgoing HTTP Response (as a streaming response)\n     * @throws javax.servlet.ServletException\n     * @throws java.io.IOException\n     */\n    private void handleRequest(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {\n        final AtomicBoolean moreDataWillBeSent = new AtomicBoolean(true);\n        Subscription sampleSubscription = null;\n\n        /* ensure we aren't allowing more connections than we want */\n        int numberConnections = incrementAndGetCurrentConcurrentConnections();\n        try {\n            int maxNumberConnectionsAllowed = getMaxNumberConcurrentConnectionsAllowed(); //may change at runtime, so look this up for each request\n            if (numberConnections > maxNumberConnectionsAllowed) {\n                response.sendError(503, \"MaxConcurrentConnections reached: \" + maxNumberConnectionsAllowed);\n            } else {\n                /* initialize response */\n                response.setHeader(\"Content-Type\", \"text/event-stream;charset=UTF-8\");\n                response.setHeader(\"Cache-Control\", \"no-cache, no-store, max-age=0, must-revalidate\");\n                response.setHeader(\"Pragma\", \"no-cache\");\n\n                final PrintWriter writer = response.getWriter();\n\n                //since the sample stream is based on Observable.interval, events will get published on an RxComputation thread\n                //since writing to the servlet response is blocking, use the Rx IO thread for the write that occurs in the onNext\n                sampleSubscription = sampleStream\n                        .observeOn(Schedulers.io())\n                        .subscribe(new Subscriber<String>() {\n                            @Override\n                            public void onCompleted() {\n                                logger.error(\"HystrixSampleSseServlet: ({}) received unexpected OnCompleted from sample stream\", getClass().getSimpleName());\n                                moreDataWillBeSent.set(false);\n                            }\n\n                            @Override\n                            public void onError(Throwable e) {\n                                moreDataWillBeSent.set(false);\n                            }\n\n                            @Override\n                            public void onNext(String sampleDataAsString) {\n                                if (sampleDataAsString != null) {\n                                    try {\n                                        // avoid concurrent writes with ping\n                                        synchronized (responseWriteLock) {\n                                            writer.print(\"data: \" + sampleDataAsString + \"\\n\\n\");\n                                            // explicitly check for client disconnect - PrintWriter does not throw exceptions\n                                            if (writer.checkError()) {\n                                                moreDataWillBeSent.set(false);\n                                            }\n                                            writer.flush();\n                                        }\n                                    } catch (Exception ex) {\n                                        moreDataWillBeSent.set(false);\n                                    }\n                                }\n                            }\n                        });\n\n                while (moreDataWillBeSent.get() && !isDestroyed) {\n                    try {\n                        Thread.sleep(pausePollerThreadDelayInMs);\n                        //in case stream has not started emitting yet, catch any clients which connect/disconnect before emits start\n\n                        // avoid concurrent writes with sample\n                        synchronized (responseWriteLock) {\n                            writer.print(\"ping: \\n\\n\");\n                            // explicitly check for client disconnect - PrintWriter does not throw exceptions\n                            if (writer.checkError()) {\n                                moreDataWillBeSent.set(false);\n                            }\n                            writer.flush();\n                        }\n                    } catch (Exception ex) {\n                        moreDataWillBeSent.set(false);\n                    }\n                }\n            }\n        } finally {\n            decrementCurrentConcurrentConnections();\n            if (sampleSubscription != null && !sampleSubscription.isUnsubscribed()) {\n                sampleSubscription.unsubscribe();\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixUtilizationJsonStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.fasterxml.jackson.core.JsonFactory;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.metric.sample.HystrixCommandUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixThreadPoolUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixUtilizationStream;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.Map;\n\n/**\n * Links HystrixUtilizationStream and JSON encoding.  This may be consumed in a variety of ways:\n * -such as-\n * <ul>\n * <li> {@link HystrixUtilizationSseServlet} for mapping a specific URL to this data as an SSE stream\n * <li> Consumer of your choice that wants control over where to embed this stream\n * </ul>\n * @deprecated Instead, prefer mapping your preferred serialization on top of {@link HystrixUtilizationStream#observe()}.\n */\n@Deprecated //since 1.5.4\npublic class HystrixUtilizationJsonStream {\n    private final Func1<Integer, Observable<HystrixUtilization>> streamGenerator;\n\n    private static final JsonFactory jsonFactory = new JsonFactory();\n\n    private static final Func1<HystrixUtilization, String> convertToJsonFunc = new Func1<HystrixUtilization, String>() {\n        @Override\n        public String call(HystrixUtilization utilization) {\n            try {\n                return convertToJson(utilization);\n            } catch (IOException ioe) {\n                throw new RuntimeException(ioe);\n            }\n        }\n    };\n\n    @Deprecated //since 1.5.4\n    public HystrixUtilizationJsonStream() {\n        this.streamGenerator = new Func1<Integer, Observable<HystrixUtilization>>() {\n            @Override\n            public Observable<HystrixUtilization> call(Integer delay) {\n                return HystrixUtilizationStream.getInstance().observe();\n            }\n        };\n    }\n\n    @Deprecated //since 1.5.4\n    public HystrixUtilizationJsonStream(Func1<Integer, Observable<HystrixUtilization>> streamGenerator) {\n        this.streamGenerator = streamGenerator;\n    }\n\n    private static void writeCommandUtilizationJson(JsonGenerator json, HystrixCommandKey key, HystrixCommandUtilization utilization) throws IOException {\n        json.writeObjectFieldStart(key.name());\n        json.writeNumberField(\"activeCount\", utilization.getConcurrentCommandCount());\n        json.writeEndObject();\n    }\n\n    private static void writeThreadPoolUtilizationJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolUtilization utilization) throws IOException {\n        json.writeObjectFieldStart(threadPoolKey.name());\n        json.writeNumberField(\"activeCount\", utilization.getCurrentActiveCount());\n        json.writeNumberField(\"queueSize\", utilization.getCurrentQueueSize());\n        json.writeNumberField(\"corePoolSize\", utilization.getCurrentCorePoolSize());\n        json.writeNumberField(\"poolSize\", utilization.getCurrentPoolSize());\n        json.writeEndObject();\n    }\n\n    protected static String convertToJson(HystrixUtilization utilization) throws IOException {\n        StringWriter jsonString = new StringWriter();\n        JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n        json.writeStartObject();\n        json.writeStringField(\"type\", \"HystrixUtilization\");\n        json.writeObjectFieldStart(\"commands\");\n        for (Map.Entry<HystrixCommandKey, HystrixCommandUtilization> entry: utilization.getCommandUtilizationMap().entrySet()) {\n            final HystrixCommandKey key = entry.getKey();\n            final HystrixCommandUtilization commandUtilization = entry.getValue();\n            writeCommandUtilizationJson(json, key, commandUtilization);\n\n        }\n        json.writeEndObject();\n\n        json.writeObjectFieldStart(\"threadpools\");\n        for (Map.Entry<HystrixThreadPoolKey, HystrixThreadPoolUtilization> entry: utilization.getThreadPoolUtilizationMap().entrySet()) {\n            final HystrixThreadPoolKey threadPoolKey = entry.getKey();\n            final HystrixThreadPoolUtilization threadPoolUtilization = entry.getValue();\n            writeThreadPoolUtilizationJson(json, threadPoolKey, threadPoolUtilization);\n        }\n        json.writeEndObject();\n        json.writeEndObject();\n        json.close();\n\n        return jsonString.getBuffer().toString();\n    }\n\n    /**\n     * @deprecated Not for public use.  Using the delay param prevents streams from being efficiently shared.\n     * Please use {@link HystrixUtilizationStream#observe()}\n     * @param delay interval between data emissions\n     * @return sampled utilization as Java object, taken on a timer\n     */\n    @Deprecated //deprecated as of 1.5.4\n    public Observable<HystrixUtilization> observe(int delay) {\n        return streamGenerator.call(delay);\n    }\n\n    /**\n     * @deprecated Not for public use.  Using the delay param prevents streams from being efficiently shared.\n     * Please use {@link HystrixUtilizationStream#observe()}\n     * and the {@link #convertToJson(HystrixUtilization)} method\n     * @param delay interval between data emissions\n     * @return sampled utilization as JSON string, taken on a timer\n     */\n    public Observable<String> observeJson(int delay) {\n        return streamGenerator.call(delay).map(convertToJsonFunc);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/main/java/com/netflix/hystrix/contrib/sample/stream/HystrixUtilizationSseServlet.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.metric.sample.HystrixUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixUtilizationStream;\nimport com.netflix.hystrix.serial.SerialHystrixUtilization;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Streams Hystrix config in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-*.jar in your classpath.\n * <p>\n * 2) Adding the following to web.xml:\n * <pre>{@code\n * <servlet>\n *  <description></description>\n *  <display-name>HystrixUtilizationSseServlet</display-name>\n *  <servlet-name>HystrixUtilizationSseServlet</servlet-name>\n *  <servlet-class>com.netflix.hystrix.contrib.sample.stream.HystrixUtilizationSseServlet</servlet-class>\n * </servlet>\n * <servlet-mapping>\n *  <servlet-name>HystrixUtilizationSseServlet</servlet-name>\n *  <url-pattern>/hystrix/utilization.stream</url-pattern>\n * </servlet-mapping>\n * } </pre>\n */\npublic class HystrixUtilizationSseServlet extends HystrixSampleSseServlet {\n\n    private static final long serialVersionUID = -7812908330777694972L;\n\n    /* used to track number of connections and throttle */\n    private static AtomicInteger concurrentConnections = new AtomicInteger(0);\n    private static DynamicIntProperty maxConcurrentConnections =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n    public HystrixUtilizationSseServlet() {\n        this(HystrixUtilizationStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n    }\n\n    /* package-private */ HystrixUtilizationSseServlet(Observable<HystrixUtilization> sampleStream, int pausePollerThreadDelayInMs) {\n        super(sampleStream.map(new Func1<HystrixUtilization, String>() {\n            @Override\n            public String call(HystrixUtilization hystrixUtilization) {\n                return SerialHystrixUtilization.toJsonString(hystrixUtilization);\n            }\n        }), pausePollerThreadDelayInMs);\n    }\n\n    @Override\n    protected int getMaxNumberConcurrentConnectionsAllowed() {\n        return maxConcurrentConnections.get();\n    }\n\n    @Override\n    protected int getNumberCurrentConnections() {\n        return concurrentConnections.get();\n    }\n\n    @Override\n    protected int incrementAndGetCurrentConcurrentConnections() {\n        return concurrentConnections.incrementAndGet();\n    }\n\n    @Override\n    protected void decrementCurrentConcurrentConnections() {\n        concurrentConnections.decrementAndGet();\n    }\n}\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/test/java/com/netflix/hystrix/contrib/metrics/eventstream/HystrixMetricsPollerTest.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.eventstream;\n\nimport static org.junit.Assert.*;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * Polls Hystrix metrics and output JSON strings for each metric to a MetricsPollerListener.\n * <p>\n * Polling can be stopped/started. Use shutdown() to permanently shutdown the poller.\n */\npublic class HystrixMetricsPollerTest {\n\n    @Test\n    public void testStartStopStart() {\n        final AtomicInteger metricsCount = new AtomicInteger();\n\n        HystrixMetricsPoller poller = new HystrixMetricsPoller(new HystrixMetricsPoller.MetricsAsJsonPollerListener() {\n\n            @Override\n            public void handleJsonMetric(String json) {\n                System.out.println(\"Received: \" + json);\n                metricsCount.incrementAndGet();\n            }\n        }, 100);\n        try {\n\n            HystrixCommand<Boolean> test = new HystrixCommand<Boolean>(HystrixCommandGroupKey.Factory.asKey(\"HystrixMetricsPollerTest\")) {\n\n                @Override\n                protected Boolean run() {\n                    return true;\n                }\n\n            };\n            test.execute();\n\n            poller.start();\n\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n            int v1 = metricsCount.get();\n\n            assertTrue(v1 > 0);\n\n            poller.pause();\n\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n            int v2 = metricsCount.get();\n\n            // they should be the same since we were paused\n            System.out.println(\"First poll got : \" + v1 + \", second got : \" + v2);\n            assertTrue(v2 == v1);\n\n            poller.start();\n\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n            int v3 = metricsCount.get();\n\n            // we should have more metrics again\n            assertTrue(v3 > v1);\n\n        } finally {\n            poller.shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/test/java/com/netflix/hystrix/contrib/metrics/eventstream/HystrixMetricsStreamServletUnitTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.eventstream;\n\nimport com.netflix.hystrix.metric.consumer.HystrixDashboardStream;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class HystrixMetricsStreamServletUnitTest {\n\n    @Mock HttpServletRequest mockReq;\n    @Mock HttpServletResponse mockResp;\n    @Mock HystrixDashboardStream.DashboardData mockDashboard;\n    @Mock PrintWriter mockPrintWriter;\n\n    HystrixMetricsStreamServlet servlet;\n\n    private final Observable<HystrixDashboardStream.DashboardData> streamOfOnNexts =\n            Observable.interval(100, TimeUnit.MILLISECONDS).map(new Func1<Long, HystrixDashboardStream.DashboardData>() {\n                @Override\n                public HystrixDashboardStream.DashboardData call(Long timestamp) {\n                    return mockDashboard;\n                }\n            });\n\n\n    @Before\n    public void init() {\n        MockitoAnnotations.initMocks(this);\n        when(mockReq.getMethod()).thenReturn(\"GET\");\n    }\n\n    @After\n    public void tearDown() {\n        servlet.destroy();\n        servlet.shutdown();\n    }\n\n    @Test\n    public void shutdownServletShouldRejectRequests() throws ServletException, IOException {\n        servlet = new HystrixMetricsStreamServlet(streamOfOnNexts, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        servlet.shutdown();\n\n        servlet.service(mockReq, mockResp);\n\n        verify(mockResp).sendError(503, \"Service has been shut down.\");\n    }\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/test/java/com/netflix/hystrix/contrib/sample/stream/HystrixConfigSseServletTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\nimport org.mockito.MockitoAnnotations;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\nimport rx.schedulers.Schedulers;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class HystrixConfigSseServletTest {\n\n    @Mock HttpServletRequest mockReq;\n    @Mock HttpServletResponse mockResp;\n    @Mock HystrixConfiguration mockConfig;\n    @Mock PrintWriter mockPrintWriter;\n\n    HystrixConfigSseServlet servlet;\n\n    private final Observable<HystrixConfiguration> streamOfOnNexts = Observable.interval(100, TimeUnit.MILLISECONDS).map(new Func1<Long, HystrixConfiguration>() {\n        @Override\n        public HystrixConfiguration call(Long timestamp) {\n            return mockConfig;\n        }\n    });\n\n    private final Observable<HystrixConfiguration> streamOfOnNextThenOnError = Observable.create(new Observable.OnSubscribe<HystrixConfiguration>() {\n        @Override\n        public void call(Subscriber<? super HystrixConfiguration> subscriber) {\n            try {\n                Thread.sleep(100);\n                subscriber.onNext(mockConfig);\n                Thread.sleep(100);\n                subscriber.onError(new RuntimeException(\"stream failure\"));\n            } catch (InterruptedException ex) {\n                ex.printStackTrace();\n            }\n        }\n    }).subscribeOn(Schedulers.computation());\n\n    private final Observable<HystrixConfiguration> streamOfOnNextThenOnCompleted = Observable.create(new Observable.OnSubscribe<HystrixConfiguration>() {\n        @Override\n        public void call(Subscriber<? super HystrixConfiguration> subscriber) {\n            try {\n                Thread.sleep(100);\n                subscriber.onNext(mockConfig);\n                Thread.sleep(100);\n                subscriber.onCompleted();\n            } catch (InterruptedException ex) {\n                ex.printStackTrace();\n            }\n        }\n    }).subscribeOn(Schedulers.computation());\n\n    @Before\n    public void init() {\n        MockitoAnnotations.initMocks(this);\n    }\n\n    @After\n    public void tearDown() {\n        servlet.destroy();\n        servlet.shutdown();\n    }\n\n    @Test\n    public void shutdownServletShouldRejectRequests() throws ServletException, IOException {\n        servlet = new HystrixConfigSseServlet(streamOfOnNexts, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        servlet.shutdown();\n\n        servlet.doGet(mockReq, mockResp);\n\n        verify(mockResp).sendError(503, \"Service has been shut down.\");\n    }\n\n    @Test\n    public void testConfigDataWithInfiniteOnNextStream() throws IOException, InterruptedException {\n        servlet = new HystrixConfigSseServlet(streamOfOnNexts, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        final AtomicInteger writes = new AtomicInteger(0);\n\n        when(mockReq.getParameter(\"delay\")).thenReturn(\"100\");\n        when(mockResp.getWriter()).thenReturn(mockPrintWriter);\n        Mockito.doAnswer(new Answer<Void>() {\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                String written = (String) invocation.getArguments()[0];\n                System.out.println(\"ARG : \" + written);\n\n                if (!written.contains(\"ping\")) {\n                    writes.incrementAndGet();\n                }\n                return null;\n            }\n        }).when(mockPrintWriter).print(Mockito.anyString());\n\n        Runnable simulateClient = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    servlet.doGet(mockReq, mockResp);\n                } catch (ServletException ex) {\n                    fail(ex.getMessage());\n                } catch (IOException ex) {\n                    fail(ex.getMessage());\n                }\n            }\n        };\n\n        Thread t = new Thread(simulateClient);\n        System.out.println(\"Starting thread : \" + t.getName());\n        t.start();\n        System.out.println(\"Started thread : \" + t.getName());\n\n        try {\n            Thread.sleep(1000);\n            System.out.println(\"Woke up from sleep : \" + Thread.currentThread().getName());\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        System.out.println(\"About to interrupt\");\n        t.interrupt();\n        System.out.println(\"Done interrupting\");\n\n        Thread.sleep(100);\n\n        System.out.println(\"WRITES : \" + writes.get());\n        assertTrue(writes.get() >= 9);\n        assertEquals(0, servlet.getNumberCurrentConnections());\n    }\n\n    @Test\n    public void testConfigDataWithStreamOnError() throws IOException, InterruptedException {\n        servlet = new HystrixConfigSseServlet(streamOfOnNextThenOnError, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        final AtomicInteger writes = new AtomicInteger(0);\n\n        when(mockReq.getParameter(\"delay\")).thenReturn(\"100\");\n        when(mockResp.getWriter()).thenReturn(mockPrintWriter);\n        Mockito.doAnswer(new Answer<Void>() {\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                String written = (String) invocation.getArguments()[0];\n                System.out.println(\"ARG : \" + written);\n\n                if (!written.contains(\"ping\")) {\n                    writes.incrementAndGet();\n                }\n                return null;\n            }\n        }).when(mockPrintWriter).print(Mockito.anyString());\n\n        Runnable simulateClient = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    servlet.doGet(mockReq, mockResp);\n                } catch (ServletException ex) {\n                    fail(ex.getMessage());\n                } catch (IOException ex) {\n                    fail(ex.getMessage());\n                }\n            }\n        };\n\n        Thread t = new Thread(simulateClient);\n        t.start();\n\n        try {\n            Thread.sleep(1000);\n            System.out.println(System.currentTimeMillis() + \" Woke up from sleep : \" + Thread.currentThread().getName());\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        assertEquals(1, writes.get());\n        assertEquals(0, servlet.getNumberCurrentConnections());\n    }\n\n    @Test\n    public void testConfigDataWithStreamOnCompleted() throws IOException, InterruptedException {\n        servlet = new HystrixConfigSseServlet(streamOfOnNextThenOnCompleted, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        final AtomicInteger writes = new AtomicInteger(0);\n\n        when(mockReq.getParameter(\"delay\")).thenReturn(\"100\");\n        when(mockResp.getWriter()).thenReturn(mockPrintWriter);\n        Mockito.doAnswer(new Answer<Void>() {\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                String written = (String) invocation.getArguments()[0];\n                System.out.println(\"ARG : \" + written);\n\n                if (!written.contains(\"ping\")) {\n                    writes.incrementAndGet();\n                }\n                return null;\n            }\n        }).when(mockPrintWriter).print(Mockito.anyString());\n\n        Runnable simulateClient = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    servlet.doGet(mockReq, mockResp);\n                } catch (ServletException ex) {\n                    fail(ex.getMessage());\n                } catch (IOException ex) {\n                    fail(ex.getMessage());\n                }\n            }\n        };\n\n        Thread t = new Thread(simulateClient);\n        t.start();\n\n        try {\n            Thread.sleep(1000);\n            System.out.println(System.currentTimeMillis() + \" Woke up from sleep : \" + Thread.currentThread().getName());\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        assertEquals(1, writes.get());\n        assertEquals(0, servlet.getNumberCurrentConnections());\n    }\n\n    @Test\n    public void testConfigDataWithIoExceptionOnWrite() throws IOException, InterruptedException {\n        servlet = new HystrixConfigSseServlet(streamOfOnNexts, 10);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        final AtomicInteger writes = new AtomicInteger(0);\n\n        when(mockResp.getWriter()).thenReturn(mockPrintWriter);\n        Mockito.doAnswer(new Answer<Void>() {\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                String written = (String) invocation.getArguments()[0];\n                System.out.println(\"ARG : \" + written);\n\n                if (!written.contains(\"ping\")) {\n                    writes.incrementAndGet();\n                }\n                throw new IOException(\"simulated IO Exception\");\n            }\n        }).when(mockPrintWriter).print(Mockito.anyString());\n\n        Runnable simulateClient = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    servlet.doGet(mockReq, mockResp);\n                } catch (ServletException ex) {\n                    fail(ex.getMessage());\n                } catch (IOException ex) {\n                    fail(ex.getMessage());\n                }\n            }\n        };\n\n        Thread t = new Thread(simulateClient);\n        t.start();\n\n        try {\n            Thread.sleep(1000);\n            System.out.println(System.currentTimeMillis() + \" Woke up from sleep : \" + Thread.currentThread().getName());\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        assertTrue(writes.get() <= 2);\n        assertEquals(0, servlet.getNumberCurrentConnections());\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream/src/test/java/com/netflix/hystrix/contrib/sample/stream/HystrixSampleSseServletTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.sample.stream;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixConfigurationStream;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\nimport org.mockito.MockitoAnnotations;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.regex.Pattern;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\nimport rx.schedulers.Schedulers;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.when;\n\npublic class HystrixSampleSseServletTest {\n\n    private static final String INTERJECTED_CHARACTER = \"a\";\n\n    @Mock HttpServletRequest mockReq;\n    @Mock HttpServletResponse mockResp;\n    @Mock HystrixConfiguration mockConfig;\n    @Mock PrintWriter mockPrintWriter;\n\n    TestHystrixConfigSseServlet servlet;\n\n    @Before\n    public void init() {\n        MockitoAnnotations.initMocks(this);\n    }\n\n    @After\n    public void tearDown() {\n        servlet.destroy();\n        servlet.shutdown();\n    }\n\n    @Test\n    public void testNoConcurrentResponseWrites() throws IOException, InterruptedException {\n        final Observable<HystrixConfiguration> limitedOnNexts = Observable.create(new Observable.OnSubscribe<HystrixConfiguration>() {\n            @Override\n            public void call(Subscriber<? super HystrixConfiguration> subscriber) {\n                try {\n                    for (int i = 0; i < 500; i++) {\n                        Thread.sleep(10);\n                        subscriber.onNext(mockConfig);\n                    }\n\n                } catch (InterruptedException ex) {\n                    ex.printStackTrace();\n                } catch (Exception e) {\n                    subscriber.onCompleted();\n                }\n            }\n        }).subscribeOn(Schedulers.computation());\n\n        servlet = new TestHystrixConfigSseServlet(limitedOnNexts, 1);\n        try {\n            servlet.init();\n        } catch (ServletException ex) {\n\n        }\n\n        final StringBuilder buffer = new StringBuilder();\n\n        when(mockReq.getParameter(\"delay\")).thenReturn(\"100\");\n        when(mockResp.getWriter()).thenReturn(mockPrintWriter);\n        Mockito.doAnswer(new Answer<Void>() {\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                String written = (String) invocation.getArguments()[0];\n                if (written.contains(\"ping\")) {\n                    buffer.append(INTERJECTED_CHARACTER);\n                } else {\n                    // slow down the append to increase chances to interleave\n                    for (int i = 0; i < written.length(); i++) {\n                        Thread.sleep(5);\n                        buffer.append(written.charAt(i));\n                    }\n                }\n                return null;\n            }\n        }).when(mockPrintWriter).print(Mockito.anyString());\n\n        Runnable simulateClient = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    servlet.doGet(mockReq, mockResp);\n                } catch (ServletException ex) {\n                    fail(ex.getMessage());\n                } catch (IOException ex) {\n                    fail(ex.getMessage());\n                }\n            }\n        };\n\n        Thread t = new Thread(simulateClient);\n        t.start();\n\n        try {\n            Thread.sleep(1000);\n            System.out.println(System.currentTimeMillis() + \" Woke up from sleep : \" + Thread.currentThread().getName());\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        Pattern pattern = Pattern.compile(\"\\\\{[\" + INTERJECTED_CHARACTER + \"]+\\\\}\");\n        boolean hasInterleaved = pattern.matcher(buffer).find();\n        assertFalse(hasInterleaved);\n    }\n\n    private static class TestHystrixConfigSseServlet extends HystrixSampleSseServlet {\n\n        private static AtomicInteger concurrentConnections = new AtomicInteger(0);\n        private static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n        public TestHystrixConfigSseServlet() {\n            this(HystrixConfigurationStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n        }\n\n        TestHystrixConfigSseServlet(Observable<HystrixConfiguration> sampleStream, int pausePollerThreadDelayInMs) {\n            super(sampleStream.map(new Func1<HystrixConfiguration, String>() {\n                @Override\n                public String call(HystrixConfiguration hystrixConfiguration) {\n                    return \"{}\";\n                }\n            }), pausePollerThreadDelayInMs);\n        }\n\n        @Override\n        protected int getMaxNumberConcurrentConnectionsAllowed() {\n            return maxConcurrentConnections.get();\n        }\n\n        @Override\n        protected int getNumberCurrentConnections() {\n            return concurrentConnections.get();\n        }\n\n        @Override\n        protected int incrementAndGetCurrentConcurrentConnections() {\n            return concurrentConnections.incrementAndGet();\n        }\n\n        @Override\n        protected void decrementCurrentConcurrentConnections() {\n            concurrentConnections.decrementAndGet();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/README.md",
    "content": "# hystrix-metrics-event-stream-jaxrs\n\nThis module is a JAX-RS implementation of [hystrix-metrics-event-stream](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-metrics-event-stream) module without any Servlet API dependency and exposes metrics in a [text/event-stream](https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events) formatted stream that continues as long as a client holds the connection.\n\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-metrics-event-stream-jaxrs%22).\n\nExample for Maven ([lookup latest version](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-metrics-event-stream-jaxrs%22)):\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-metrics-event-stream-jaxrs</artifactId>\n    <version>1.6.0</version>\n</dependency>\n```\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-metrics-event-stream-jaxrs\" rev=\"1.6.0\" />\n```\n\n# Installation\n\n1) Include hystrix-metrics-event-stream-jaxrs*.jar in your classpath (such as /WEB-INF/lib). \n2) Register `HystrixStreamFeature` in your `javax.ws.rs.core.Application` as shown below.\n\n```java\n\npublic class HystrixStreamApplication extends Application{\n\n    @Override\n    public Set<Class<?>> getClasses() {\n\t\t\tSet<Class<?>> clazzes = new HashSet<Class<?>>();\n\t\t\tclazzes.add(HystrixStreamFeature.class);\n\t\t\treturn clazzes;\n   }\n}\n```\n\n3) Following end-points are available\n  * /hystrix.stream - Stream Hystrix Metrics\n  * /hystrix/utilization.stream - Stream Hystrix Utilization\n  * /hystrix/config.stream - Stream Hystrix configuration\n  * /hystrix/request.stream - Stream Hystrix SSE events\n  \n\n\n# Test\n\nTo test your installation you can use curl like this:\n\n```\n$ curl http://hostname:port/appname/hystrix.stream\n\ndata: {\"rollingCountFailure\":0,\"propertyValue_executionIsolationThreadInterruptOnTimeout\":true,\"rollingCountTimeout\":0,\"rollingCountExceptionsThrown\":0,\"rollingCountFallbackSuccess\":0,\"errorCount\":0,\"type\":\"HystrixCommand\",\"propertyValue_circuitBreakerEnabled\":true,\"reportingHosts\":1,\"latencyTotal\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"currentConcurrentExecutionCount\":0,\"rollingCountSemaphoreRejected\":0,\"rollingCountFallbackRejection\":0,\"rollingCountShortCircuited\":0,\"rollingCountResponsesFromCache\":0,\"propertyValue_circuitBreakerForceClosed\":false,\"name\":\"IdentityCookieAuthSwitchProfile\",\"propertyValue_executionIsolationThreadPoolKeyOverride\":\"null\",\"rollingCountSuccess\":0,\"propertyValue_requestLogEnabled\":true,\"requestCount\":0,\"rollingCountCollapsedRequests\":0,\"errorPercentage\":0,\"propertyValue_circuitBreakerSleepWindowInMilliseconds\":5000,\"latencyTotal_mean\":0,\"propertyValue_circuitBreakerForceOpen\":false,\"propertyValue_circuitBreakerRequestVolumeThreshold\":20,\"propertyValue_circuitBreakerErrorThresholdPercentage\":50,\"propertyValue_executionIsolationStrategy\":\"THREAD\",\"rollingCountFallbackFailure\":0,\"isCircuitBreakerOpen\":false,\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\":20,\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\":1000,\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\":10000,\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\":10,\"latencyExecute\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"group\":\"IDENTITY\",\"latencyExecute_mean\":0,\"propertyValue_requestCacheEnabled\":true,\"rollingCountThreadPoolRejected\":0}\n\ndata: {\"rollingCountFailure\":0,\"propertyValue_executionIsolationThreadInterruptOnTimeout\":true,\"rollingCountTimeout\":0,\"rollingCountExceptionsThrown\":0,\"rollingCountFallbackSuccess\":0,\"errorCount\":0,\"type\":\"HystrixCommand\",\"propertyValue_circuitBreakerEnabled\":true,\"reportingHosts\":3,\"latencyTotal\":{\"0\":1,\"95\":1,\"99.5\":1,\"90\":1,\"25\":1,\"99\":1,\"75\":1,\"100\":1,\"50\":1},\"currentConcurrentExecutionCount\":0,\"rollingCountSemaphoreRejected\":0,\"rollingCountFallbackRejection\":0,\"rollingCountShortCircuited\":0,\"rollingCountResponsesFromCache\":0,\"propertyValue_circuitBreakerForceClosed\":false,\"name\":\"CryptexDecrypt\",\"propertyValue_executionIsolationThreadPoolKeyOverride\":\"null\",\"rollingCountSuccess\":1,\"propertyValue_requestLogEnabled\":true,\"requestCount\":1,\"rollingCountCollapsedRequests\":0,\"errorPercentage\":0,\"propertyValue_circuitBreakerSleepWindowInMilliseconds\":15000,\"latencyTotal_mean\":1,\"propertyValue_circuitBreakerForceOpen\":false,\"propertyValue_circuitBreakerRequestVolumeThreshold\":60,\"propertyValue_circuitBreakerErrorThresholdPercentage\":150,\"propertyValue_executionIsolationStrategy\":\"THREAD\",\"rollingCountFallbackFailure\":0,\"isCircuitBreakerOpen\":false,\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\":60,\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\":3000,\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\":30000,\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\":30,\"latencyExecute\":{\"0\":0,\"95\":0,\"99.5\":0,\"90\":0,\"25\":0,\"99\":0,\"75\":0,\"100\":0,\"50\":0},\"group\":\"CRYPTEX\",\"latencyExecute_mean\":0,\"propertyValue_requestCacheEnabled\":true,\"rollingCountThreadPoolRejected\":0}\n```\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n\timplementation project(':hystrix-serialization')\n    compileOnly 'javax.ws.rs:javax.ws.rs-api:2.0.1'\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation 'org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:2.25.1'\n\ttestImplementation 'org.glassfish.jersey.media:jersey-media-sse:2.25.1'\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/HystrixStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport rx.Observable;\n\n/**\n * @author justinjose28\n * \n */\npublic final class HystrixStream {\n\tprivate final Observable<String> sampleStream;\n\tprivate final int pausePollerThreadDelayInMs;\n\tprivate final AtomicInteger concurrentConnections;\n\n\tpublic HystrixStream(Observable<String> sampleStream, int pausePollerThreadDelayInMs, AtomicInteger concurrentConnections) {\n\t\tthis.sampleStream = sampleStream;\n\t\tthis.pausePollerThreadDelayInMs = pausePollerThreadDelayInMs;\n\t\tthis.concurrentConnections = concurrentConnections;\n\t}\n\n\tpublic Observable<String> getSampleStream() {\n\t\treturn sampleStream;\n\t}\n\n\tpublic int getPausePollerThreadDelayInMs() {\n\t\treturn pausePollerThreadDelayInMs;\n\t}\n\n\tpublic AtomicInteger getConcurrentConnections() {\n\t\treturn concurrentConnections;\n\t}\n\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/HystrixStreamFeature.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics;\n\nimport javax.ws.rs.core.Feature;\nimport javax.ws.rs.core.FeatureContext;\n\nimport com.netflix.hystrix.contrib.metrics.controller.HystrixConfigSseController;\nimport com.netflix.hystrix.contrib.metrics.controller.HystrixMetricsStreamController;\nimport com.netflix.hystrix.contrib.metrics.controller.HystrixRequestEventsSseController;\nimport com.netflix.hystrix.contrib.metrics.controller.HystrixUtilizationSseController;\n\n/**\n * @author justinjose28\n * \n */\npublic class HystrixStreamFeature implements Feature {\n\n\t@Override\n\tpublic boolean configure(FeatureContext context) {\n\t\tcontext.register(new HystrixMetricsStreamController());\n\t\tcontext.register(new HystrixUtilizationSseController());\n\t\tcontext.register(new HystrixRequestEventsSseController());\n\t\tcontext.register(new HystrixConfigSseController());\n\t\tcontext.register(HystrixStreamingOutputProvider.class);\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/HystrixStreamingOutputProvider.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.ext.MessageBodyWriter;\nimport javax.ws.rs.ext.Provider;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.schedulers.Schedulers;\n\n/**\n * {@link MessageBodyWriter} implementation which handles serialization of HystrixStream\n * \n * \n * @author justinjose28\n * \n */\n\n@Provider\npublic class HystrixStreamingOutputProvider implements MessageBodyWriter<HystrixStream> {\n\n\tprivate static final Logger LOGGER = LoggerFactory.getLogger(HystrixStreamingOutputProvider.class);\n\n\t@Override\n\tpublic boolean isWriteable(Class<?> t, Type gt, Annotation[] as, MediaType mediaType) {\n\t\treturn HystrixStream.class.isAssignableFrom(t);\n\t}\n\n\t@Override\n\tpublic long getSize(HystrixStream o, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {\n\t\treturn -1;\n\t}\n\n\t@Override\n\tpublic void writeTo(HystrixStream o, Class<?> t, Type gt, Annotation[] as, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, final OutputStream entity) throws IOException {\n\t\tSubscription sampleSubscription = null;\n\t\tfinal AtomicBoolean moreDataWillBeSent = new AtomicBoolean(true);\n\t\ttry {\n\n\t\t\tsampleSubscription = o.getSampleStream().observeOn(Schedulers.io()).subscribe(new Subscriber<String>() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onCompleted() {\n\t\t\t\t\tLOGGER.error(\"HystrixSampleSseServlet: ({}) received unexpected OnCompleted from sample stream\", getClass().getSimpleName());\n\t\t\t\t\tmoreDataWillBeSent.set(false);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onError(Throwable e) {\n\t\t\t\t\tmoreDataWillBeSent.set(false);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onNext(String sampleDataAsString) {\n\t\t\t\t\tif (sampleDataAsString != null) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentity.write((\"data: \" + sampleDataAsString + \"\\n\\n\").getBytes());\n\t\t\t\t\t\t\tentity.flush();\n\t\t\t\t\t\t} catch (IOException ioe) {\n\t\t\t\t\t\t\tmoreDataWillBeSent.set(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\twhile (moreDataWillBeSent.get()) {\n\t\t\t\ttry {\n\t\t\t\t\tThread.sleep(o.getPausePollerThreadDelayInMs());\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\tmoreDataWillBeSent.set(false);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\to.getConcurrentConnections().decrementAndGet();\n\t\t\tif (sampleSubscription != null && !sampleSubscription.isUnsubscribed()) {\n\t\t\t\tsampleSubscription.unsubscribe();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/controller/AbstractHystrixStreamController.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.core.HttpHeaders;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.Response.ResponseBuilder;\nimport javax.ws.rs.core.Response.Status;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport rx.Observable;\n\nimport com.netflix.hystrix.contrib.metrics.HystrixStream;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamingOutputProvider;\n\n/**\n * @author justinjose28\n * \n */\npublic abstract class AbstractHystrixStreamController {\n\tprotected final Observable<String> sampleStream;\n\n\tstatic final Logger logger = LoggerFactory.getLogger(AbstractHystrixStreamController.class);\n\n\t// wake up occasionally and check that poller is still alive. this value controls how often\n\tprotected static final int DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS = 500;\n\n\tprivate final int pausePollerThreadDelayInMs;\n\n\tprotected AbstractHystrixStreamController(Observable<String> sampleStream) {\n\t\tthis(sampleStream, DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS);\n\t}\n\n\tprotected AbstractHystrixStreamController(Observable<String> sampleStream, int pausePollerThreadDelayInMs) {\n\t\tthis.sampleStream = sampleStream;\n\t\tthis.pausePollerThreadDelayInMs = pausePollerThreadDelayInMs;\n\t}\n\n\tprotected abstract int getMaxNumberConcurrentConnectionsAllowed();\n\n\tprotected abstract AtomicInteger getCurrentConnections();\n\n\t/**\n\t * Maintain an open connection with the client. On initial connection send latest data of each requested event type and subsequently send all changes for each requested event type.\n\t * \n\t * @return JAX-RS Response - Serialization will be handled by {@link HystrixStreamingOutputProvider}\n\t */\n\tprotected Response handleRequest() {\n\t\tResponseBuilder builder = null;\n\t\t/* ensure we aren't allowing more connections than we want */\n\t\tint numberConnections = getCurrentConnections().get();\n\t\tint maxNumberConnectionsAllowed = getMaxNumberConcurrentConnectionsAllowed(); // may change at runtime, so look this up for each request\n\t\tif (numberConnections >= maxNumberConnectionsAllowed) {\n\t\t\tbuilder = Response.status(Status.SERVICE_UNAVAILABLE).entity(\"MaxConcurrentConnections reached: \" + maxNumberConnectionsAllowed);\n\t\t} else {\n\t\t\t/* initialize response */\n\t\t\tbuilder = Response.status(Status.OK);\n\t\t\tbuilder.header(HttpHeaders.CONTENT_TYPE, \"text/event-stream;charset=UTF-8\");\n\t\t\tbuilder.header(HttpHeaders.CACHE_CONTROL, \"no-cache, no-store, max-age=0, must-revalidate\");\n\t\t\tbuilder.header(\"Pragma\", \"no-cache\");\n\t\t\tgetCurrentConnections().incrementAndGet();\n\t\t\tbuilder.entity(new HystrixStream(sampleStream, pausePollerThreadDelayInMs, getCurrentConnections()));\n\t\t}\n\t\treturn builder.build();\n\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/controller/HystrixConfigSseController.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.GET;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.core.Application;\nimport javax.ws.rs.core.Response;\n\nimport rx.functions.Func1;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixConfigurationStream;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamFeature;\nimport com.netflix.hystrix.serial.SerialHystrixConfiguration;\n\n/**\n * Streams Hystrix config in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-jaxrs-*.jar in your classpath.\n * <p>\n * 2) Register {@link HystrixStreamFeature} in your {@link Application}.\n * <p>\n * 3) Stream will be available at path /hystrix/config.stream\n * <p>\n *\n * @author justinjose28\n * \n */\n@Path(\"/hystrix/config.stream\")\npublic class HystrixConfigSseController extends AbstractHystrixStreamController {\n\n\tprivate static final AtomicInteger concurrentConnections = new AtomicInteger(0);\n\tprivate static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n\tpublic HystrixConfigSseController() {\n\t\tsuper(HystrixConfigurationStream.getInstance().observe().map(new Func1<HystrixConfiguration, String>() {\n\t\t\t@Override\n\t\t\tpublic String call(HystrixConfiguration hystrixConfiguration) {\n\t\t\t\treturn SerialHystrixConfiguration.toJsonString(hystrixConfiguration);\n\t\t\t}\n\t\t}));\n\t}\n\n\t@GET\n\tpublic Response getStream() {\n\t\treturn handleRequest();\n\t}\n\n\t@Override\n\tprotected int getMaxNumberConcurrentConnectionsAllowed() {\n\t\treturn maxConcurrentConnections.get();\n\t}\n\n\t@Override\n\tprotected AtomicInteger getCurrentConnections()  {\n\t\treturn concurrentConnections;\n\t}\n\t\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/controller/HystrixMetricsStreamController.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.GET;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.core.Application;\nimport javax.ws.rs.core.Response;\n\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamFeature;\nimport com.netflix.hystrix.metric.consumer.HystrixDashboardStream;\nimport com.netflix.hystrix.serial.SerialHystrixDashboardData;\n\n/**\n * Streams Hystrix metrics in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-jaxrs-*.jar in your classpath.\n * <p>\n * 2) Register {@link HystrixStreamFeature} in your {@link Application}.\n * <p>\n * 3) Stream will be available at path /hystrix.stream\n * <p>\n * \n * @author justinjose28\n * \n */\n@Path(\"/hystrix.stream\")\npublic class HystrixMetricsStreamController extends AbstractHystrixStreamController {\n\n\tprivate static final AtomicInteger concurrentConnections = new AtomicInteger(0);\n\tprivate static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n\tpublic HystrixMetricsStreamController() {\n\t\tsuper(HystrixDashboardStream.getInstance().observe().concatMap(new Func1<HystrixDashboardStream.DashboardData, Observable<String>>() {\n\t\t\t@Override\n\t\t\tpublic Observable<String> call(HystrixDashboardStream.DashboardData dashboardData) {\n\t\t\t\treturn Observable.from(SerialHystrixDashboardData.toMultipleJsonStrings(dashboardData));\n\t\t\t}\n\t\t}));\n\t}\n\n\t@GET\n\tpublic Response getStream() {\n\t\treturn handleRequest();\n\t}\n\n\t@Override\n\tprotected int getMaxNumberConcurrentConnectionsAllowed() {\n\t\treturn maxConcurrentConnections.get();\n\t}\n\t@Override\n\tprotected AtomicInteger getCurrentConnections()  {\n\t\treturn concurrentConnections;\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/controller/HystrixRequestEventsSseController.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.GET;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.core.Application;\nimport javax.ws.rs.core.Response;\n\nimport rx.functions.Func1;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamFeature;\nimport com.netflix.hystrix.metric.HystrixRequestEvents;\nimport com.netflix.hystrix.metric.HystrixRequestEventsStream;\nimport com.netflix.hystrix.serial.SerialHystrixRequestEvents;\n\n/**\n * Resource that writes SSE JSON every time a request is made\n * \n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-jaxrs-*.jar in your classpath.\n * <p>\n * 2) Register {@link HystrixStreamFeature} in your {@link Application}.\n * <p>\n * 3) Stream will be available at path /hystrix/request.stream\n * <p>\n * \n * @author justinjose28\n * \n */\n@Path(\"/hystrix/request.stream\")\npublic class HystrixRequestEventsSseController extends AbstractHystrixStreamController {\n\n\tprivate static final AtomicInteger concurrentConnections = new AtomicInteger(0);\n\tprivate static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n\tpublic HystrixRequestEventsSseController() {\n\t\tsuper(HystrixRequestEventsStream.getInstance().observe().map(new Func1<HystrixRequestEvents, String>() {\n\t\t\t@Override\n\t\t\tpublic String call(HystrixRequestEvents requestEvents) {\n\t\t\t\treturn SerialHystrixRequestEvents.toJsonString(requestEvents);\n\t\t\t}\n\t\t}));\n\t}\n\n\t@GET\n\tpublic Response getStream() {\n\t\treturn handleRequest();\n\t}\n\n\t@Override\n\tprotected int getMaxNumberConcurrentConnectionsAllowed() {\n\t\treturn maxConcurrentConnections.get();\n\t}\n\n\t@Override\n\tprotected AtomicInteger getCurrentConnections()  {\n\t\treturn concurrentConnections;\n\t}\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/main/java/com/netflix/hystrix/contrib/metrics/controller/HystrixUtilizationSseController.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.GET;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.core.Application;\nimport javax.ws.rs.core.Response;\n\nimport rx.functions.Func1;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamFeature;\nimport com.netflix.hystrix.metric.sample.HystrixUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixUtilizationStream;\nimport com.netflix.hystrix.serial.SerialHystrixUtilization;\n\n/**\n * Streams Hystrix config in text/event-stream format.\n * <p>\n * Install by:\n * <p>\n * 1) Including hystrix-metrics-event-stream-jaxrs-*.jar in your classpath.\n * <p>\n * 2) Register {@link HystrixStreamFeature} in your {@link Application}.\n * <p>\n * 3) Stream will be available at path /hystrix/utilization.stream\n * <p>\n * \n * @author justinjose28\n * \n */\n@Path(\"/hystrix/utilization.stream\")\npublic class HystrixUtilizationSseController extends AbstractHystrixStreamController {\n\n\tprivate static final AtomicInteger concurrentConnections = new AtomicInteger(0);\n\tprivate static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.config.stream.maxConcurrentConnections\", 5);\n\n\tpublic HystrixUtilizationSseController() {\n\t\tsuper(HystrixUtilizationStream.getInstance().observe().map(new Func1<HystrixUtilization, String>() {\n\t\t\t@Override\n\t\t\tpublic String call(HystrixUtilization hystrixUtilization) {\n\t\t\t\treturn SerialHystrixUtilization.toJsonString(hystrixUtilization);\n\t\t\t}\n\t\t}));\n\t}\n\n\t@GET\n\tpublic Response getStream() {\n\t\treturn handleRequest();\n\t}\n\n\t@Override\n\tprotected int getMaxNumberConcurrentConnectionsAllowed() {\n\t\treturn maxConcurrentConnections.get();\n\t}\n\t\n\t@Override\n\tprotected AtomicInteger getCurrentConnections()  {\n\t\treturn concurrentConnections;\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/test/java/com/netflix/hystrix/contrib/metrics/controller/HystricsMetricsControllerTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport static javax.ws.rs.core.MediaType.APPLICATION_JSON;\nimport static junit.framework.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.ServiceUnavailableException;\nimport javax.ws.rs.core.Application;\nimport javax.ws.rs.core.Response;\n\nimport org.apache.commons.configuration.SystemConfiguration;\nimport org.glassfish.jersey.media.sse.EventInput;\nimport org.glassfish.jersey.media.sse.InboundEvent;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.test.JerseyTest;\nimport org.glassfish.jersey.test.TestProperties;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamFeature;\n\n/**\n * @author justinjose28\n * \n */\n@Path(\"/hystrix\")\npublic class HystricsMetricsControllerTest extends JerseyTest {\n\tprotected static final AtomicInteger requestCount = new AtomicInteger(0);\n\n\t@POST\n\t@Path(\"/command\")\n\t@Consumes(APPLICATION_JSON)\n\tpublic void command() throws Exception {\n\t\tTestHystrixCommand command = new TestHystrixCommand();\n\t\tcommand.execute();\n\t}\n\n\t@Override\n\tprotected Application configure() {\n\t\tint port = 0;\n\t\ttry {\n\t\t\tfinal ServerSocket socket = new ServerSocket(0);\n\t\t\tport = socket.getLocalPort();\n\t\t\tsocket.close();\n\t\t} catch (IOException e1) {\n\t\t\tthrow new RuntimeException(\"Failed to find port to start test server\");\n\t\t}\n\t\tset(TestProperties.CONTAINER_PORT, port);\n\t\ttry {\n\t\t\tSystemConfiguration.setSystemProperties(\"test.properties\");\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(\"Failed to load config file\");\n\t\t}\n\t\treturn new ResourceConfig(HystricsMetricsControllerTest.class, HystrixStreamFeature.class);\n\t}\n\n\tprotected String getPath() {\n\t\treturn \"hystrix.stream\";\n\t}\n\n\tprotected boolean isStreamValid(String data) {\n\t\treturn data.contains(\"\\\"type\\\":\\\"HystrixThreadPool\\\"\") && data.contains(\"\\\"currentCompletedTaskCount\\\":\" + requestCount.get());\n\t}\n\n\t@Test\n\tpublic void testInfiniteStream() throws Exception {\n\t\texecuteHystrixCommand(); // Execute a Hystrix command so that metrics are initialized.\n\t\tEventInput stream = getStream(); // Invoke Stream API which returns a steady stream output.\n\t\ttry {\n\t\t\tvalidateStream(stream, 1000); // Validate the stream.\n\t\t\tSystem.out.println(\"Validated Stream Output 1\");\n\t\t\texecuteHystrixCommand(); // Execute Hystrix Command again so that request count is updated.\n\t\t\tvalidateStream(stream, 1000); // Stream should show updated request count\n\t\t\tSystem.out.println(\"Validated Stream Output 2\");\n\t\t} finally {\n\t\t\tif (stream != null) {\n\t\t\t\tstream.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testConcurrency() throws Exception {\n\t\texecuteHystrixCommand(); // Execute a Hystrix command so that metrics are initialized.\n\t\tList<EventInput> streamList = new ArrayList<EventInput>();\n\t\ttry {\n\t\t\t// Fire 3 requests, validate their responses and hold these connections.\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\tEventInput stream = getStream();\n\t\t\t\tSystem.out.println(\"Received Response for Request#\" + (i + 1));\n\t\t\t\tstreamList.add(stream);\n\t\t\t\tvalidateStream(stream, 1000);\n\t\t\t\tSystem.out.println(\"Validated Response#\" + (i + 1));\n\t\t\t}\n\n\t\t\t// Fourth request should fail since max configured connection is 3.\n\t\t\ttry {\n\t\t\t\tstreamList.add(getStreamFailFast());\n\t\t\t\tAssert.fail(\"Expected 'ServiceUnavailableException' but, request went through.\");\n\t\t\t} catch (ServiceUnavailableException e) {\n\t\t\t\tSystem.out.println(\"Got ServiceUnavailableException as expected.\");\n\t\t\t}\n\n\t\t\t// Close one of the connections\n\t\t\tstreamList.get(0).close();\n\t\t\tstreamList.remove(0);\n\n\t\t\t// Try again after closing one of the connections. This request should go through.\n\t\t\tEventInput eventInput = getStream();\n\t\t\tstreamList.add(eventInput);\n\t\t\tvalidateStream(eventInput, 1000);\n\t\t} finally {\n\t\t\tfor (EventInput stream : streamList) {\n\t\t\t\tif (stream != null) {\n\t\t\t\t\tstream.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate void executeHystrixCommand() throws Exception {\n\t\tResponse response = target(\"hystrix/command\").request().post(null);\n\t\tassertEquals(204, response.getStatus());\n\t\tSystem.out.println(\"Hystrix Command ran successfully.\");\n\t\trequestCount.incrementAndGet();\n\t}\n\n\tprivate EventInput getStream() throws Exception {\n\t\tlong timeElapsed = System.currentTimeMillis();\n\t\twhile (System.currentTimeMillis() - timeElapsed < 3000) {\n\t\t\ttry {\n\t\t\t\treturn getStreamFailFast();\n\t\t\t} catch (Exception e) {\n\n\t\t\t}\n\t\t}\n\t\tfail(\"Not able to connect to Stream end point\");\n\t\treturn null;\n\t}\n\n\tprivate EventInput getStreamFailFast() throws Exception {\n\t\treturn target(getPath()).request().get(EventInput.class);\n\t}\n\n\tprivate void validateStream(EventInput eventInput, long waitTime) {\n\t\tlong timeElapsed = System.currentTimeMillis();\n\t\twhile (!eventInput.isClosed() && System.currentTimeMillis() - timeElapsed < waitTime) {\n\t\t\tfinal InboundEvent inboundEvent = eventInput.read();\n\t\t\tif (inboundEvent == null) {\n\t\t\t\tAssert.fail(\"Failed while verifying stream. Looks like connection has been closed.\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tString data = inboundEvent.readData(String.class);\n\t\t\tSystem.out.println(data);\n\t\t\tif (isStreamValid(data)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tAssert.fail(\"Failed while verifying stream\");\n\t}\n\n\tpublic static class TestHystrixCommand extends HystrixCommand<Void> {\n\n\t\tprotected TestHystrixCommand() {\n\t\t\tsuper(HystrixCommandGroupKey.Factory.asKey(\"test\"));\n\t\t}\n\n\t\t@Override\n\t\tprotected Void run() throws Exception {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/test/java/com/netflix/hystrix/contrib/metrics/controller/HystrixConfigControllerTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\n/**\n * @author justinjose28\n * \n */\npublic class HystrixConfigControllerTest extends HystricsMetricsControllerTest {\n\n\t@Override\n\tprotected String getPath() {\n\t\treturn \"hystrix/config.stream\";\n\t}\n\n\t@Override\n\tprotected boolean isStreamValid(String data) {\n\t\treturn data.contains(\"\\\"type\\\":\\\"HystrixConfig\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/test/java/com/netflix/hystrix/contrib/metrics/controller/HystrixUtilizationControllerTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\n/**\n * @author justinjose28\n *\n */\npublic class HystrixUtilizationControllerTest extends HystricsMetricsControllerTest {\n\n\t@Override\n\tprotected String getPath() {\n\t\treturn \"hystrix/utilization.stream\";\n\t}\n\n\t@Override\n\tprotected boolean isStreamValid(String data) {\n\t\treturn data.contains(\"\\\"type\\\":\\\"HystrixUtilization\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/test/java/com/netflix/hystrix/contrib/metrics/controller/StreamingOutputProviderTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.metrics.controller;\n\nimport static junit.framework.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.ws.rs.core.HttpHeaders;\nimport javax.ws.rs.core.Response;\n\nimport org.junit.Test;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func1;\nimport rx.schedulers.Schedulers;\n\nimport com.netflix.hystrix.contrib.metrics.HystrixStream;\nimport com.netflix.hystrix.contrib.metrics.HystrixStreamingOutputProvider;\n\npublic class StreamingOutputProviderTest {\n\n\tprivate final Observable<String> streamOfOnNexts = Observable.interval(100, TimeUnit.MILLISECONDS).map(new Func1<Long, String>() {\n\t\t@Override\n\t\tpublic String call(Long timestamp) {\n\t\t\treturn \"test-stream\";\n\t\t}\n\t});\n\n\tprivate final Observable<String> streamOfOnNextThenOnError = Observable.create(new Observable.OnSubscribe<String>() {\n\t\t@Override\n\t\tpublic void call(Subscriber<? super String> subscriber) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(100);\n\t\t\t\tsubscriber.onNext(\"test-stream\");\n\t\t\t\tThread.sleep(100);\n\t\t\t\tsubscriber.onError(new RuntimeException(\"stream failure\"));\n\t\t\t} catch (InterruptedException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t}\n\t}).subscribeOn(Schedulers.computation());\n\n\tprivate final Observable<String> streamOfOnNextThenOnCompleted = Observable.create(new Observable.OnSubscribe<String>() {\n\t\t@Override\n\t\tpublic void call(Subscriber<? super String> subscriber) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(100);\n\t\t\t\tsubscriber.onNext(\"test-stream\");\n\t\t\t\tThread.sleep(100);\n\t\t\t\tsubscriber.onCompleted();\n\t\t\t} catch (InterruptedException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t}\n\t}).subscribeOn(Schedulers.computation());\n\n\tprivate AbstractHystrixStreamController sse = new AbstractHystrixStreamController(streamOfOnNexts) {\n\t\tprivate  final AtomicInteger concurrentConnections = new AtomicInteger(0);\n\t\t@Override\n\t\tprotected int getMaxNumberConcurrentConnectionsAllowed() {\n\t\t\treturn 2;\n\t\t}\n\t\t@Override\n\t\tprotected AtomicInteger getCurrentConnections() {\n\t\t\treturn concurrentConnections;\n\t\t}\n\n\t};\n\n\t@Test\n\tpublic void concurrencyTest() throws Exception {\n\n\t\tResponse resp = sse.handleRequest();\n\t\tassertEquals(200, resp.getStatus());\n\t\tassertEquals(\"text/event-stream;charset=UTF-8\", resp.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE));\n\t\tassertEquals(\"no-cache, no-store, max-age=0, must-revalidate\", resp.getHeaders().getFirst(HttpHeaders.CACHE_CONTROL));\n\t\tassertEquals(\"no-cache\", resp.getHeaders().getFirst(\"Pragma\"));\n\n\t\tresp = sse.handleRequest();\n\t\tassertEquals(200, resp.getStatus());\n\n\t\tresp = sse.handleRequest();\n\t\tassertEquals(503, resp.getStatus());\n\t\tassertEquals(\"MaxConcurrentConnections reached: \" + sse.getMaxNumberConcurrentConnectionsAllowed(), resp.getEntity());\n\n\t\tsse.getCurrentConnections().decrementAndGet();\n\n\t\tresp = sse.handleRequest();\n\t\tassertEquals(200, resp.getStatus());\n\t}\n\n\t@Test\n\tpublic void testInfiniteOnNextStream() throws Exception {\n\t\tfinal PipedInputStream is = new PipedInputStream();\n\t\tfinal PipedOutputStream os = new PipedOutputStream(is);\n\t\tfinal AtomicInteger writes = new AtomicInteger(0);\n\t\tfinal HystrixStream stream = new HystrixStream(streamOfOnNexts, 100, new AtomicInteger(1));\n\t\tThread streamingThread = startStreamingThread(stream, os);\n\t\tverifyStream(is, writes);\n\t\tThread.sleep(1000); // Let the provider stream for some time.\n\t\tstreamingThread.interrupt(); // Stop streaming\n\n\t\tos.close();\n\t\tis.close();\n\n\t\tSystem.out.println(\"Total lines:\" + writes.get());\n\t\tassertTrue(writes.get() >= 9); // Observable is configured to emit events in every 100 ms. So expect at least 9 in a second.\n\n\t\t// Provider is expected to decrement connection count when streaming process is terminated.\n\t\tassertTrue(hasNoMoreConcurrentConnections(stream.getConcurrentConnections(), 200, 10, TimeUnit.MILLISECONDS));\n\t}\n\n\t@Test\n\tpublic void testOnError() throws Exception {\n\t\ttestStreamOnce(streamOfOnNextThenOnError);\n\t}\n\n\t@Test\n\tpublic void testOnComplete() throws Exception {\n\t\ttestStreamOnce(streamOfOnNextThenOnCompleted);\n\t}\n\n\t// as the concurrentConnections count is decremented asynchronously, we need to potentially give the check a little bit of time\n\tprivate static boolean hasNoMoreConcurrentConnections(AtomicInteger concurrentConnectionsCount, long waitDuration, long pollInterval, TimeUnit timeUnit) throws InterruptedException {\n\t\tlong period = (pollInterval > waitDuration) ? waitDuration : pollInterval;\n\n\t\tfor (long i = 0; i < waitDuration; i += period) {\n\t\t\tif (concurrentConnectionsCount.get() == 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tThread.sleep(timeUnit.toMillis(period));\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate void testStreamOnce(Observable<String> observable) throws Exception {\n\t\tfinal PipedInputStream is = new PipedInputStream();\n\t\tfinal PipedOutputStream os = new PipedOutputStream(is);\n\t\tfinal AtomicInteger writes = new AtomicInteger(0);\n\t\tfinal HystrixStream stream = new HystrixStream(observable, 100, new AtomicInteger(1));\n\t\tstartStreamingThread(stream, os);\n\t\tverifyStream(is, writes);\n\t\tThread.sleep(1000);\n\n\t\tos.close();\n\t\tis.close();\n\n\t\tSystem.out.println(\"Total lines:\" + writes.get());\n\t\tassertTrue(writes.get() == 1);\n\n\t\tassertTrue(hasNoMoreConcurrentConnections(stream.getConcurrentConnections(), 200, 10, TimeUnit.MILLISECONDS));\n\t}\n\n\tprivate static Thread startStreamingThread(final HystrixStream stream, final OutputStream outputSteam) {\n\t\tThread th1 = new Thread(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tfinal HystrixStreamingOutputProvider provider = new HystrixStreamingOutputProvider();\n\t\t\t\t\tprovider.writeTo(stream, null, null, null, null, null, outputSteam);\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tfail(e.getMessage());\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tth1.start();\n\t\treturn th1;\n\t}\n\n\tprivate static void verifyStream(final InputStream is, final AtomicInteger lineCount) {\n\t\tThread th2 = new Thread(new Runnable() {\n\t\t\tpublic void run() {\n\t\t\t\tBufferedReader br = null;\n\t\t\t\ttry {\n\t\t\t\t\tbr = new BufferedReader(new InputStreamReader(is));\n\t\t\t\t\tString line;\n\t\t\t\t\twhile ((line = br.readLine()) != null) {\n\t\t\t\t\t\tif (!\"\".equals(line)) {\n\t\t\t\t\t\t\tSystem.out.println(line);\n\t\t\t\t\t\t\tlineCount.incrementAndGet();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tfail(\"Failed while verifying streaming output.Stacktrace:\" + e.getMessage());\n\t\t\t\t} finally {\n\t\t\t\t\tif (br != null) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tbr.close();\n\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\tfail(\"Failed while verifying streaming output.Stacktrace:\" + e.getMessage());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t});\n\t\tth2.start();\n\t}\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-metrics-event-stream-jaxrs/src/test/resources/test.properties",
    "content": "hystrix.stream.utilization.intervalInMilliseconds=10\nhystrix.stream.dashboard.intervalInMilliseconds=10\nhystrix.stream.config.intervalInMilliseconds=10\nhystrix.config.stream.maxConcurrentConnections=3\n"
  },
  {
    "path": "hystrix-contrib/hystrix-network-auditor-agent/README.md",
    "content": "# Hystrix Network Auditor Agent\n\nOriginal Issue: https://github.com/Netflix/Hystrix/issues/116\n\nThis is a [Java Agent](http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html) that instruments network access to allow auditing whether it is being performed within the context of Hystrix or not.\n\nThe intent is to enable building a listener to:\n\n- find unknown vulnerabilities (network traffic that was unknown)\n- track \"drift\" over time as transitive dependencies pull in code that performs network access\n- track metrics and optionally provide alerts\n- allow failing a canary build if unexpected network access occurs\n- alert in production if unexpected network access starts (such as if a property is flipped to turn on a feature)\n\n\n# Why?\n\nThis module originates out of work to deal with the \"unknowns\" that continue to cause failure after wrapping all known network access in Hystrix.\n\nThe Netflix API team successfully eliminated a large percentage of the class of errors and outages caused by network latency to backend services but maintaining this state of protection is difficult with constantly changing code and 3rd party libraries.\n\nIn other words it's easy to either be unaware of a vulnerability or \"[drift into failure](http://www.amazon.com/Drift-into-Failure-ebook/dp/B009KOKXKY/ref=tmm_kin_title_0)\" as the state of the system changes over time.\n\n\n# How to Use\n\n1) Enable the Java Agent\n\nAdd the following to the JVM command-line:\n\n```\n-javaagent:/var/root/hystrix-network-auditor-agent-x.y.zjar\n```\n\nThis will be loaded in the boot classloader and instrument `java.net` and `java.io` classes.\n\n2) Register an Event Listener\n\nIn the application register a listener to be invoked on each network event:\n\n```java\ncom.netflix.hystrix.contrib.networkauditor.HystrixNetworkAuditorAgent.registerEventListener(eventListener)\n```\n\n3) Handle Events\n\nIt is up to the application to decide what to do but generally it is expected that an implementation will filter to only calls not wrapped in Hystrix and then determine the stack trace so the code path can be identified.\n\nHere is an example that increments an overall counter and records the stack trace with a counter per unique stack trace:\n\n```java\n    @Override\n    public void handleNetworkEvent() {\n        if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n            // increment counter\n            totalNonIsolatedEventsCounter.increment();\n            // capture the stacktrace and record so network events can be debugged and tracked down\n            StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n            HystrixNetworkEvent counter = counters.get(stack);\n            if (counter == null) {\n                counter = new HystrixNetworkEvent(stack);\n                HystrixNetworkEvent c = counters.putIfAbsent(Arrays.toString(stack), counter);\n                if (c != null) {\n                    // another thread beat us\n                    counter = c;\n                }\n            }\n            counter.increment();\n        }\n    }\n```\n\n# Deployment Model\n\nThis is not expected to run on all production instances but as part of a canary process.\n\nFor example the Netflix API team intends to have long-running canaries using this agent and treat it like \"canaries in the coalmine\" that are always running and alert us if network traffic shows up that we are not aware of and not wrapped by Hystrix.\n\nMore information about experience will come over time ... this is open-source so we're developing in public!\n"
  },
  {
    "path": "hystrix-contrib/hystrix-network-auditor-agent/build.gradle",
    "content": "dependencies {\n    api 'org.javassist:javassist:3.19+'\n\n    jar {\n        // make a fatjar otherwise it's painful getting the boot-class-path correct when deploying\n        from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }\n        manifest {\n            attributes( \n                \"Agent-Class\": \"com.netflix.hystrix.contrib.networkauditor.HystrixNetworkAuditorAgent\", \n                \"Can-Redefine-Classes\": true, \n                \"Can-Retransform-Classes\": true, \n                \"Boot-Class-Path\": \"hystrix-network-auditor-agent-\" + version + \".jar\",\n                \"Premain-Class\": \"com.netflix.hystrix.contrib.networkauditor.HystrixNetworkAuditorAgent\")\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-network-auditor-agent/src/main/java/com/netflix/hystrix/contrib/networkauditor/HystrixNetworkAuditorAgent.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.networkauditor;\n\nimport java.lang.instrument.Instrumentation;\n\n/**\n * Java Agent to instrument network code in the java.* libraries and use Hystrix state to determine if calls are Hystrix-isolated or not.\n */\npublic class HystrixNetworkAuditorAgent {\n\n    private static final HystrixNetworkAuditorEventListener DEFAULT_BRIDGE = new HystrixNetworkAuditorEventListener() {\n\n        @Override\n        public void handleNetworkEvent() {\n            // do nothing\n        }\n\n    };\n    private static volatile HystrixNetworkAuditorEventListener bridge = DEFAULT_BRIDGE;\n\n    public static void premain(String agentArgs, Instrumentation inst) {\n        inst.addTransformer(new NetworkClassTransform());\n    }\n\n    /**\n     * Invoked by instrumented code when network access occurs.\n     */\n    public static void notifyOfNetworkEvent() {\n        bridge.handleNetworkEvent();\n    }\n\n    /**\n     * Register the implementation of the {@link HystrixNetworkAuditorEventListener} that will receive the events.\n     * \n     * @param bridge\n     *            {@link HystrixNetworkAuditorEventListener} implementation\n     */\n    public static void registerEventListener(HystrixNetworkAuditorEventListener bridge) {\n        if (bridge == null) {\n            throw new IllegalArgumentException(\"HystrixNetworkAuditorEventListener can not be NULL\");\n        }\n        HystrixNetworkAuditorAgent.bridge = bridge;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-network-auditor-agent/src/main/java/com/netflix/hystrix/contrib/networkauditor/HystrixNetworkAuditorEventListener.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.networkauditor;\n\n/**\n * Event listener that gets implemented and registered  with {@link HystrixNetworkAuditorAgent#registerEventListener(HystrixNetworkAuditorEventListener)} by the application \n * running Hystrix in the application classloader into this JavaAgent running in the boot classloader so events can be invoked on code inside the application classloader.\n */\npublic interface HystrixNetworkAuditorEventListener {\n\n    /**\n     * Invoked by the {@link HystrixNetworkAuditorAgent} when network events occur.\n     * <p>\n     * An event may be the opening of a socket, channel or reading/writing bytes. It is not guaranteed to be a one-to-one relationship with a request/response.\n     * <p>\n     * No arguments are returned as it is left to the implementation to decide whether the current thread stacktrace should be captured or not.\n     * <p>\n     * Typical implementations will want to filter to non-Hystrix isolated network traffic with code such as this:\n     * \n     * <pre> {@code\n     * \n     * if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n     *      // this event is not inside a Hystrix context (according to ThreadLocal variables)\n     *      StackTraceElement[] stack = Thread.currentThread().getStackTrace();\n     *      // increment counters, fire alerts, log stack traces etc\n     * }\n     * } </pre>\n     * \n     */\n    public void handleNetworkEvent();\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-network-auditor-agent/src/main/java/com/netflix/hystrix/contrib/networkauditor/NetworkClassTransform.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.networkauditor;\n\nimport java.io.IOException;\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.IllegalClassFormatException;\nimport java.security.ProtectionDomain;\n\nimport javassist.CannotCompileException;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.CtConstructor;\nimport javassist.CtMethod;\nimport javassist.NotFoundException;\n\n/**\n * Bytecode ClassFileTransformer used by the Java Agent to instrument network code in the java.* libraries and use Hystrix state to determine if calls are Hystrix-isolated or not.\n */\npublic class NetworkClassTransform implements ClassFileTransformer {\n\n    @Override\n    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {\n        String name = className.replace('/', '.');\n        try {\n            /*\n             * These hook points were found through trial-and-error after wrapping all java.net/java.io/java.nio classes and methods and finding reliable\n             * notifications that matched statistics and events in an application.\n             * \n             * There may very well be problems here or code paths that don't correctly trigger an event.\n             * \n             * If someone can provide a more reliable and cleaner hook point or if there are examples of code paths that don't trigger either of these\n             * then please file a bug or submit a pull request at https://github.com/Netflix/Hystrix\n             */\n            if (name.equals(\"java.net.Socket$2\")) {\n                // this one seems to be fairly reliable in counting each time a request/response occurs on blocking IO\n                return wrapConstructorsOfClass(name);\n            } else if (name.equals(\"java.nio.channels.SocketChannel\")) {\n                // handle NIO \n                return wrapConstructorsOfClass(name);\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed trying to wrap class: \" + className, e);\n        }\n\n        // we didn't transform anything so return null to leave untouched\n        return null;\n    }\n\n    /**\n     * Wrap all constructors of a given class\n     * \n     * @param className\n     * @throws NotFoundException\n     * @throws CannotCompileException\n     * @throws IOException\n     */\n    private byte[] wrapConstructorsOfClass(String className) throws NotFoundException, IOException, CannotCompileException {\n        return wrapClass(className, true);\n    }\n\n    /**\n     * Wrap all signatures of a given method name.\n     * \n     * @param className\n     * @param methodName\n     * @throws NotFoundException\n     * @throws CannotCompileException\n     * @throws IOException\n     */\n    private byte[] wrapClass(String className, boolean wrapConstructors, String... methodNames) throws NotFoundException, IOException, CannotCompileException {\n        ClassPool cp = ClassPool.getDefault();\n        CtClass ctClazz = cp.get(className);\n        // constructors\n        if (wrapConstructors) {\n            CtConstructor[] constructors = ctClazz.getConstructors();\n            for (CtConstructor constructor : constructors) {\n                try {\n                    constructor.insertBefore(\"{ com.netflix.hystrix.contrib.networkauditor.HystrixNetworkAuditorAgent.notifyOfNetworkEvent(); }\");\n                } catch (Exception e) {\n                    throw new RuntimeException(\"Failed trying to wrap constructor of class: \" + className, e);\n                }\n\n            }\n        }\n        // methods\n        CtMethod[] methods = ctClazz.getDeclaredMethods();\n        for (CtMethod method : methods) {\n            try {\n                for (String methodName : methodNames) {\n                    if (method.getName().equals(methodName)) {\n                        method.insertBefore(\"{ com.netflix.hystrix.contrib.networkauditor.HystrixNetworkAuditorAgent.handleNetworkEvent(); }\");\n                    }\n                }\n            } catch (Exception e) {\n                throw new RuntimeException(\"Failed trying to wrap method [\" + method.getName() + \"] of class: \" + className, e);\n            }\n        }\n        return ctClazz.toBytecode();\n    }\n\n}"
  },
  {
    "path": "hystrix-contrib/hystrix-request-servlet/README.md",
    "content": "# Hystrix Request Servlet Filters\n\nThis module contains functional examples for a J2EE/Servlet environment that initialize and uses  [HystrixRequestContext](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestContext.java).\n\nYou can use this module as is or model your own implementation after it as these classes are very basic.\n\nIf using a framework that doesn't use Servlets, or a framework with other lifecycle hooks you may need to implement your own anyways.\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-request-servlet%22).\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-request-servlet</artifactId>\n    <version>1.1.2</version>\n</dependency>\n```\n\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-request-servlet\" rev=\"1.1.2\" />\n```\n\n# Installation\n\n## [HystrixRequestContextServletFilter](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestContextServletFilter.java)\n\nThis initializes the [HystrixRequestContext](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestContext.java) at the beginning of each HTTP request and then cleans it up at the end.\n\nYou install it by adding the following to your web.xml:\n\n```xml\n  <filter>\n    <display-name>HystrixRequestContextServletFilter</display-name>\n    <filter-name>HystrixRequestContextServletFilter</filter-name>\n    <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class>\n  </filter>\n  <filter-mapping>\n    <filter-name>HystrixRequestContextServletFilter</filter-name>\n    <url-pattern>/*</url-pattern>\n  </filter-mapping>\n```\n\n### [HystrixRequestLogViaLoggerServletFilter](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestLogViaLoggerServletFilter.java)\n\nThis logs an INFO message with the output from [HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixRequestLog.html#getExecutedCommandsAsString(\\)) at the end of each requet.\n\nYou install it by adding the following to your web.xml:\n\n```xml\n  <filter>\n    <display-name>HystrixRequestLogViaLoggerServletFilter</display-name>\n    <filter-name>HystrixRequestLogViaLoggerServletFilter</filter-name>\n    <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaLoggerServletFilter</filter-class>\n  </filter>\n  <filter-mapping>\n    <filter-name>HystrixRequestLogViaLoggerServletFilter</filter-name>\n    <url-pattern>/*</url-pattern>\n  </filter-mapping>\n```\n\n\n### [HystrixRequestLogViaResponseHeaderServletFilter](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestLogViaResponseHeaderServletFilter.java)\n\nThis adds the output of [HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixRequestLog.html#getExecutedCommandsAsString(\\)) to the HTTP response as header \"X-HystrixLog\".\n\nNote that this will not work if the response has been flushed already (such as on a progressively rendered page).\n\n```xml\n  <filter>\n    <display-name>HystrixRequestLogViaResponseHeaderServletFilter</display-name>\n    <filter-name>HystrixRequestLogViaResponseHeaderServletFilter</filter-name>\n    <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaResponseHeaderServletFilter</filter-class>\n  </filter>\n  <filter-mapping>\n    <filter-name>HystrixRequestLogViaResponseHeaderServletFilter</filter-name>\n    <url-pattern>/*</url-pattern>\n  </filter-mapping>\n```\n\n"
  },
  {
    "path": "hystrix-contrib/hystrix-request-servlet/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n    compileOnly 'javax.servlet:servlet-api:2.5'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestContextServletFilter.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.requestservlet;\n\nimport java.io.IOException;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Initializes the {@link HystrixRequestContext} at the beginning of each HTTP request and then cleans it up at the end.\n * <p>\n * Install by adding the following lines to your project web.xml:\n * <p>\n * \n * <pre>\n * {@code\n *   <filter>\n *     <display-name>HystrixRequestContextServletFilter</display-name>\n *     <filter-name>HystrixRequestContextServletFilter</filter-name>\n *     <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class>\n *   </filter>\n *   <filter-mapping>\n *     <filter-name>HystrixRequestContextServletFilter</filter-name>\n *     <url-pattern>/*</url-pattern>\n *   </filter-mapping>\n * }\n * </pre>\n */\npublic class HystrixRequestContextServletFilter implements Filter {\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            chain.doFilter(request, response);\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void destroy() {\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestLogViaLoggerServletFilter.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.requestservlet;\n\nimport java.io.IOException;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Log an INFO message with the output from <code>HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()</code> at the end of each requet.\n * <p>\n * A pre-requisite is that {@link HystrixRequestContext} is initialized, such as by using {@link HystrixRequestContextServletFilter}.\n * <p>\n * Install by adding the following lines to your project web.xml:\n * <p>\n * \n * <pre>\n * {@code\n *   <filter>\n *     <display-name>HystrixRequestLogViaLoggerServletFilter</display-name>\n *     <filter-name>HystrixRequestLogViaLoggerServletFilter</filter-name>\n *     <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaLoggerServletFilter</filter-class>\n *   </filter>\n *   <filter-mapping>\n *     <filter-name>HystrixRequestLogViaLoggerServletFilter</filter-name>\n *     <url-pattern>/*</url-pattern>\n *   </filter-mapping>\n * }\n * </pre>\n * <p>\n * NOTE: This filter must complete before {@link HystrixRequestContext} is shutdown otherwise the {@link HystrixRequestLog} will already be cleared.\n * <p>\n * This will output a log line similar to this:\n * \n * <pre>\n * Hystrix Executions [POST /order] => CreditCardCommand[SUCCESS][1122ms]\n * </pre>\n */\npublic class HystrixRequestLogViaLoggerServletFilter implements Filter {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixRequestLogViaLoggerServletFilter.class);\n\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n        StringBuilder requestURL = new StringBuilder();\n        try {\n            // get the requested URL for our logging so it can be associated to a particular request\n            String uri = ((HttpServletRequest) request).getRequestURI();\n            String queryString = ((HttpServletRequest) request).getQueryString();\n            String method = ((HttpServletRequest) request).getMethod();\n            requestURL.append(method).append(\" \").append(uri);\n            if (queryString != null) {\n                requestURL.append(\"?\").append(queryString);\n            }\n            chain.doFilter(request, response);\n        } finally {\n            try {\n                if (HystrixRequestContext.isCurrentThreadInitialized()) {\n                    HystrixRequestLog log = HystrixRequestLog.getCurrentRequest();\n                    logger.info(\"Hystrix Executions [{}] => {}\", requestURL.toString(), log.getExecutedCommandsAsString());\n                }\n            } catch (Exception e) {\n                logger.warn(\"Unable to append HystrixRequestLog\", e);\n            }\n\n        }\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void destroy() {\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-request-servlet/src/main/java/com/netflix/hystrix/contrib/requestservlet/HystrixRequestLogViaResponseHeaderServletFilter.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.requestservlet;\n\nimport java.io.IOException;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Add <code>HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()</code> to response as header \"X-HystrixLog\".\n * <p>\n * This will not work if the response has been flushed already.\n * <p>\n * A pre-requisite is that {@link HystrixRequestContext} is initialized, such as by using {@link HystrixRequestContextServletFilter}.\n * <p>\n * Install by adding the following lines to your project web.xml:\n * <p>\n * \n * <pre>\n * {@code\n *   <filter>\n *     <display-name>HystrixRequestLogViaResponseHeaderServletFilter</display-name>\n *     <filter-name>HystrixRequestLogViaResponseHeaderServletFilter</filter-name>\n *     <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaResponseHeaderServletFilter</filter-class>\n *   </filter>\n *   <filter-mapping>\n *     <filter-name>HystrixRequestLogServletFilter</filter-name>\n *     <url-pattern>/*</url-pattern>\n *   </filter-mapping>\n * }\n * </pre>\n */\npublic class HystrixRequestLogViaResponseHeaderServletFilter implements Filter {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixRequestLogViaResponseHeaderServletFilter.class);\n\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n        try {\n            chain.doFilter(request, response);\n        } finally {\n            try {\n                if (HystrixRequestContext.isCurrentThreadInitialized()) {\n                    HystrixRequestLog log = HystrixRequestLog.getCurrentRequest();\n                    if (log != null) {\n                        ((HttpServletResponse) response).addHeader(\"X-HystrixLog\", log.getExecutedCommandsAsString());\n                    }\n                }\n            } catch (Exception e) {\n                logger.warn(\"Unable to append HystrixRequestLog\", e);\n            }\n\n        }\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void destroy() {\n\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-rx-netty-metrics-stream/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n\timplementation project(':hystrix-serialization')\n    api 'io.reactivex:rxnetty:0.4.17'\n    implementation 'io.netty:netty-transport:4.1.3.Final'\n    implementation 'io.netty:netty-buffer:4.1.3.Final'\n    implementation 'io.netty:netty-codec-http:4.1.3.Final'\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation 'org.powermock:powermock-easymock-release-full:1.5.5'\n    testImplementation 'org.easymock:easymock:3.2'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-rx-netty-metrics-stream/src/main/java/com/netflix/hystrix/contrib/rxnetty/metricsstream/HystrixMetricsStreamHandler.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.rxnetty.metricsstream;\n\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.serial.SerialHystrixDashboardData;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.UnpooledByteBufAllocator;\nimport io.reactivex.netty.protocol.http.server.HttpServerRequest;\nimport io.reactivex.netty.protocol.http.server.HttpServerResponse;\nimport io.reactivex.netty.protocol.http.server.RequestHandler;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.functions.Action1;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.Subject;\nimport rx.subscriptions.MultipleAssignmentSubscription;\n\nimport java.nio.charset.Charset;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Streams Hystrix metrics in Server Sent Event (SSE) format. RxNetty application handlers shall\n * be wrapped by this handler. It transparently intercepts HTTP requests at a configurable path\n * (default \"/hystrix.stream\"), and sends unbounded SSE streams back to the client. All other requests\n * are transparently forwarded to the application handlers.\n * <p/>\n * For RxNetty client tapping into SSE stream: remember to use unpooled HTTP connections. If not, the pooled HTTP\n * connection will not be closed on unsubscribe event and the event stream will continue to flow towards the client\n * (unless the client is shutdown).\n *\n * @author Tomasz Bak\n * @author Christian Schmitt <c.schmitt@envisia.de>\n */\npublic class HystrixMetricsStreamHandler<I, O> implements RequestHandler<I, O> {\n\n    public static final String DEFAULT_HYSTRIX_PREFIX = \"/hystrix.stream\";\n\n    public static final int DEFAULT_INTERVAL = 2000;\n\n    private static final byte[] HEADER = \"data: \".getBytes(Charset.defaultCharset());\n    private static final byte[] FOOTER = {10, 10};\n    private static final int EXTRA_SPACE = HEADER.length + FOOTER.length;\n\n    private final String hystrixPrefix;\n    private final long interval;\n    private final RequestHandler<I, O> appHandler;\n\n    public HystrixMetricsStreamHandler(RequestHandler<I, O> appHandler) {\n        this(DEFAULT_HYSTRIX_PREFIX, DEFAULT_INTERVAL, appHandler);\n    }\n\n    HystrixMetricsStreamHandler(String hystrixPrefix, long interval, RequestHandler<I, O> appHandler) {\n        this.hystrixPrefix = hystrixPrefix;\n        this.interval = interval;\n        this.appHandler = appHandler;\n    }\n\n    @Override\n    public Observable<Void> handle(HttpServerRequest<I> request, HttpServerResponse<O> response) {\n        if (request.getPath().startsWith(hystrixPrefix)) {\n            return handleHystrixRequest(response);\n        }\n        return appHandler.handle(request, response);\n    }\n\n    private Observable<Void> handleHystrixRequest(final HttpServerResponse<O> response) {\n        writeHeaders(response);\n\n        final Subject<Void, Void> subject = PublishSubject.create();\n        final MultipleAssignmentSubscription subscription = new MultipleAssignmentSubscription();\n        Subscription actionSubscription = Observable.interval(interval, TimeUnit.MILLISECONDS)\n                .subscribe(new Action1<Long>() {\n                    @Override\n                    public void call(Long tick) {\n                        if (!response.getChannel().isOpen()) {\n                            subscription.unsubscribe();\n                            return;\n                        }\n                        try {\n                            for (HystrixCommandMetrics commandMetrics : HystrixCommandMetrics.getInstances()) {\n                                writeMetric(SerialHystrixDashboardData.toJsonString(commandMetrics), response);\n                            }\n                            for (HystrixThreadPoolMetrics threadPoolMetrics : HystrixThreadPoolMetrics.getInstances()) {\n                                writeMetric(SerialHystrixDashboardData.toJsonString(threadPoolMetrics), response);\n                            }\n                            for (HystrixCollapserMetrics collapserMetrics : HystrixCollapserMetrics.getInstances()) {\n                                writeMetric(SerialHystrixDashboardData.toJsonString(collapserMetrics), response);\n                            }\n                        } catch (Exception e) {\n                            subject.onError(e);\n                        }\n                    }\n                });\n        subscription.set(actionSubscription);\n        return subject;\n    }\n\n    private void writeHeaders(HttpServerResponse<O> response) {\n        response.getHeaders().add(\"Content-Type\", \"text/event-stream;charset=UTF-8\");\n        response.getHeaders().add(\"Cache-Control\", \"no-cache, no-store, max-age=0, must-revalidate\");\n        response.getHeaders().add(\"Pragma\", \"no-cache\");\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void writeMetric(String json, HttpServerResponse<O> response) {\n        byte[] bytes = json.getBytes(Charset.defaultCharset());\n        ByteBuf byteBuf = UnpooledByteBufAllocator.DEFAULT.buffer(bytes.length + EXTRA_SPACE);\n        byteBuf.writeBytes(HEADER);\n        byteBuf.writeBytes(bytes);\n        byteBuf.writeBytes(FOOTER);\n        response.writeAndFlush((O) byteBuf);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-rx-netty-metrics-stream/src/test/java/com/netflix/hystrix/HystrixCommandMetricsSamples.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifierDefault;\n\n/**\n * Not very elegant, but there is no other way to create this data directly for testing\n * purposes, as {@link com.netflix.hystrix.HystrixCommandMetrics} has no public constructors,\n * only package private.\n *\n * @author Tomasz Bak\n */\npublic class HystrixCommandMetricsSamples {\n\n    public static final HystrixCommandMetrics SAMPLE_1;\n\n    private static class MyHystrixCommandKey implements HystrixCommandKey {\n        @Override\n        public String name() {\n            return \"hystrixKey\";\n        }\n    }\n\n    private static class MyHystrixCommandGroupKey implements HystrixCommandGroupKey {\n        @Override\n        public String name() {\n            return \"hystrixCommandGroupKey\";\n        }\n    }\n\n    private static class MyHystrixThreadPoolKey implements HystrixThreadPoolKey {\n        @Override\n        public String name() {\n            return \"hystrixThreadPoolKey\";\n        }\n    }\n\n    private static class MyHystrixCommandProperties extends HystrixCommandProperties {\n        protected MyHystrixCommandProperties(HystrixCommandKey key) {\n            super(key);\n        }\n    }\n\n    static {\n        HystrixCommandKey key = new MyHystrixCommandKey();\n        SAMPLE_1 = new HystrixCommandMetrics(key, new MyHystrixCommandGroupKey(), new MyHystrixThreadPoolKey(),\n                new MyHystrixCommandProperties(key), HystrixEventNotifierDefault.getInstance());\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-rx-netty-metrics-stream/src/test/java/com/netflix/hystrix/contrib/rxnetty/metricsstream/HystrixMetricsStreamHandlerTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.rxnetty.metricsstream;\n\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandMetricsSamples;\nimport io.netty.buffer.ByteBuf;\nimport io.reactivex.netty.RxNetty;\nimport io.reactivex.netty.pipeline.PipelineConfigurators;\nimport io.reactivex.netty.protocol.http.client.HttpClient;\nimport io.reactivex.netty.protocol.http.client.HttpClientRequest;\nimport io.reactivex.netty.protocol.http.client.HttpClientResponse;\nimport io.reactivex.netty.protocol.http.server.HttpServer;\nimport io.reactivex.netty.protocol.http.server.HttpServerRequest;\nimport io.reactivex.netty.protocol.http.server.HttpServerResponse;\nimport io.reactivex.netty.protocol.http.server.RequestHandler;\nimport io.reactivex.netty.protocol.http.sse.ServerSentEvent;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.powermock.core.classloader.annotations.PrepareForTest;\nimport org.powermock.modules.junit4.PowerMockRunner;\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\nimport static com.netflix.hystrix.contrib.rxnetty.metricsstream.HystrixMetricsStreamHandler.*;\nimport static org.easymock.EasyMock.*;\nimport static org.junit.Assert.*;\nimport static org.powermock.api.easymock.PowerMock.*;\n\n/**\n * @author Tomasz Bak\n */\n@RunWith(PowerMockRunner.class)\n@PrepareForTest(HystrixCommandMetrics.class)\npublic class HystrixMetricsStreamHandlerTest {\n\n    private static final ObjectMapper mapper = new ObjectMapper();\n\n    private static Collection<HystrixCommandMetrics> SAMPLE_HYSTRIX_COMMAND_METRICS =\n            Collections.singleton(HystrixCommandMetricsSamples.SAMPLE_1);\n\n    private int port;\n    private HttpServer<ByteBuf, ByteBuf> server;\n    private HttpClient<ByteBuf, ServerSentEvent> client;\n\n    @Before\n    public void setUp() throws Exception {\n        server = createServer();\n\n        client = RxNetty.<ByteBuf, ServerSentEvent>newHttpClientBuilder(\"localhost\", port)\n                .withNoConnectionPooling()\n                .pipelineConfigurator(PipelineConfigurators.<ByteBuf>clientSseConfigurator())\n                .build();\n\n        mockStatic(HystrixCommandMetrics.class);\n        expect(HystrixCommandMetrics.getInstances()).andReturn(SAMPLE_HYSTRIX_COMMAND_METRICS).anyTimes();\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if (server != null) {\n            server.shutdown();\n        }\n        if (client != null) {\n            client.shutdown();\n        }\n    }\n\n    @Test\n    public void testMetricsAreDeliveredAsSseStream() throws Exception {\n        replayAll();\n\n        Observable<ServerSentEvent> objectObservable = client.submit(HttpClientRequest.createGet(DEFAULT_HYSTRIX_PREFIX))\n                .flatMap(new Func1<HttpClientResponse<ServerSentEvent>, Observable<? extends ServerSentEvent>>() {\n                    @Override\n                    public Observable<? extends ServerSentEvent> call(HttpClientResponse<ServerSentEvent> httpClientResponse) {\n                        return httpClientResponse.getContent().take(1);\n                    }\n                });\n\n        Object first = Observable.amb(objectObservable, Observable.timer(5000, TimeUnit.MILLISECONDS)).toBlocking().first();\n\n        assertTrue(\"Expected SSE message\", first instanceof ServerSentEvent);\n        ServerSentEvent sse = (ServerSentEvent) first;\n        JsonNode jsonNode = mapper.readTree(sse.contentAsString());\n        assertEquals(\"Expected hystrix key name\", HystrixCommandMetricsSamples.SAMPLE_1.getCommandKey().name(), jsonNode.get(\"name\").asText());\n    }\n\n    // We try a few times in case we hit into used port.\n    private HttpServer<ByteBuf, ByteBuf> createServer() {\n        Random random = new Random();\n        Exception error = null;\n        for (int i = 0; i < 3 && server == null; i++) {\n            port = 10000 + random.nextInt(50000);\n            try {\n                return RxNetty.newHttpServerBuilder(port, new HystrixMetricsStreamHandler<ByteBuf, ByteBuf>(\n                        DEFAULT_HYSTRIX_PREFIX,\n                        DEFAULT_INTERVAL,\n                        new RequestHandler<ByteBuf, ByteBuf>() {  // Application handler\n                            @Override\n                            public Observable<Void> handle(HttpServerRequest<ByteBuf> request, HttpServerResponse<ByteBuf> response) {\n                                return Observable.empty();\n                            }\n                        }\n                )).build().start();\n            } catch (Exception e) {\n                error = e;\n            }\n        }\n        throw new RuntimeException(\"Cannot initialize RxNetty server\", error);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/README.md",
    "content": "# hystrix-servo-metrics-publisher\n\nThis is an implementation of [HystrixMetricsPublisher](http://netflix.github.com/Hystrix/javadoc/index.html?com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisher.html) that publishes metrics using [Netflix Servo](https://github.com/Netflix/servo).\n\nServo enables metrics to be exposed via JMX or published to Graphite or CloudWatch.\n\nSee the [Metrics & Monitoring](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring) Wiki for more information.\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-servo-metrics-publisher%22).\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-servo-metrics-publisher</artifactId>\n    <version>1.1.2</version>\n</dependency>\n```\n\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-servo-metrics-publisher\" rev=\"1.1.2\" />\n```\n\n#Example Publishing metrics to Graphite\n\nSome minimal Servo configuration must be done during application startup (ie time of Hystrix plugin registration) to enable Servo to publish Hystrix metrics to Graphite:\n\n```java\n// Registry plugin with hystrix\nHystrixPlugins.getInstance().registerMetricsPublisher(HystrixServoMetricsPublisher.getInstance());\n        \n   ........\n        \n// Minimal Servo configuration for publishing to Graphite\nfinal List<MetricObserver> observers = new ArrayList<MetricObserver>();\n\nobservers.add(new GraphiteMetricObserver(getHostName(), \"graphite-server.example.com:2003\"));\nPollScheduler.getInstance().start();\nPollRunnable task = new PollRunnable(new MonitorRegistryMetricPoller(), BasicMetricFilter.MATCH_ALL, true, observers);\nPollScheduler.getInstance().addPoller(task, 5, TimeUnit.SECONDS);\n```\n\nIt's that simple.  See [Servo wiki](https://github.com/Netflix/servo/wiki/Getting-Started) and [Publishing to Graphite](https://github.com/Netflix/servo/wiki/Publishing-to-Graphite) for full documentation.\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n    api 'com.netflix.servo:servo-core:0.10.1'\n\ttestImplementation 'junit:junit-dep:4.10'\n\ttestImplementation 'org.mockito:mockito-all:1.9.5'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisher.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\n\n/**\n * Servo implementation of {@link HystrixMetricsPublisher}.\n * <p>\n * See <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">Wiki docs</a> about plugins for more information.\n */\npublic class HystrixServoMetricsPublisher extends HystrixMetricsPublisher {\n\n    private static HystrixServoMetricsPublisher INSTANCE = null;\n\n    public static HystrixServoMetricsPublisher getInstance() {\n        if (INSTANCE == null) {\n            HystrixServoMetricsPublisher temp = createInstance();\n            INSTANCE = temp;\n        }\n        return INSTANCE;\n    }\n\n    private static synchronized HystrixServoMetricsPublisher createInstance() {\n        if (INSTANCE == null) {\n            return new HystrixServoMetricsPublisher();\n        } else {\n            return INSTANCE;\n        }\n    }\n\n    private HystrixServoMetricsPublisher() {\n    }\n\n    @Override\n    public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        return new HystrixServoMetricsPublisherCommand(commandKey, commandGroupKey, metrics, circuitBreaker, properties);\n    }\n\n    @Override\n    public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        return new HystrixServoMetricsPublisherThreadPool(threadPoolKey, metrics, properties);\n    }\n\n    @Override\n    public HystrixMetricsPublisherCollapser getMetricsPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        return new HystrixServoMetricsPublisherCollapser(collapserKey, metrics, properties);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisherAbstract.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixMetrics;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport com.netflix.servo.annotations.DataSourceLevel;\nimport com.netflix.servo.annotations.DataSourceType;\nimport com.netflix.servo.monitor.AbstractMonitor;\nimport com.netflix.servo.monitor.Counter;\nimport com.netflix.servo.monitor.Gauge;\nimport com.netflix.servo.monitor.Monitor;\nimport com.netflix.servo.monitor.MonitorConfig;\nimport com.netflix.servo.tag.Tag;\n\n/**\n * Utility used for Servo (https://github.com/Netflix/servo) based implementations of metrics publishers.\n */\n/* package */abstract class HystrixServoMetricsPublisherAbstract {\n\n    protected abstract Tag getServoTypeTag();\n\n    protected abstract Tag getServoInstanceTag();\n\n    protected abstract class InformationalMetric<K> extends AbstractMonitor<K> {\n        public InformationalMetric(MonitorConfig config) {\n            super(config.withAdditionalTag(DataSourceType.INFORMATIONAL).withAdditionalTag(getServoTypeTag()).withAdditionalTag(getServoInstanceTag()));\n        }\n\n        @Override\n        public K getValue(int n) { \n            return getValue();\n        }\n\n        @Override\n        public abstract K getValue();\n    }\n\n    protected abstract class CounterMetric extends AbstractMonitor<Number> implements Counter {\n        public CounterMetric(MonitorConfig config) {\n            super(config.withAdditionalTag(DataSourceType.COUNTER).withAdditionalTag(getServoTypeTag()).withAdditionalTag(getServoInstanceTag()));\n        }\n\n        @Override\n        public Number getValue(int n) { \n            return getValue();\n        }\n\n        @Override\n        public abstract Number getValue();\n\n        @Override\n        public void increment() {\n            throw new IllegalStateException(\"We are wrapping a value instead.\");\n        }\n\n        @Override\n        public void increment(long arg0) {\n            throw new IllegalStateException(\"We are wrapping a value instead.\");\n        }\n    }\n\n    protected abstract class GaugeMetric extends AbstractMonitor<Number> implements Gauge<Number> {\n        public GaugeMetric(MonitorConfig config) {\n            super(config.withAdditionalTag(DataSourceType.GAUGE).withAdditionalTag(getServoTypeTag()).withAdditionalTag(getServoInstanceTag()));\n        }\n\n        @Override\n        public Number getValue(int n) { \n            return getValue();\n        }\n\n        @Override\n        public abstract Number getValue();\n    }\n\n    protected Monitor<?> getCumulativeCountForEvent(String name, final HystrixMetrics metrics, final HystrixRollingNumberEvent event) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                return metrics.getCumulativeCount(event);\n            }\n\n        };\n    }\n\n    protected Monitor<?> getRollingCountForEvent(String name, final HystrixMetrics metrics, final HystrixRollingNumberEvent event) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getRollingCount(event);\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisherCollapser.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.consumer.CumulativeCollapserEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingCollapserBatchSizeDistributionStream;\nimport com.netflix.hystrix.metric.consumer.RollingCollapserEventCounterStream;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.servo.DefaultMonitorRegistry;\nimport com.netflix.servo.annotations.DataSourceLevel;\nimport com.netflix.servo.monitor.BasicCompositeMonitor;\nimport com.netflix.servo.monitor.Monitor;\nimport com.netflix.servo.monitor.MonitorConfig;\nimport com.netflix.servo.tag.Tag;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherCollapser} using Servo (https://github.com/Netflix/servo)\n */\npublic class HystrixServoMetricsPublisherCollapser extends HystrixServoMetricsPublisherAbstract implements HystrixMetricsPublisherCollapser {\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixServoMetricsPublisherCollapser.class);\n\n    private final HystrixCollapserKey key;\n    private final HystrixCollapserMetrics metrics;\n    private final HystrixCollapserProperties properties;\n    private final Tag servoInstanceTag;\n    private final Tag servoTypeTag;\n\n    public HystrixServoMetricsPublisherCollapser(HystrixCollapserKey threadPoolKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        this.key = threadPoolKey;\n        this.metrics = metrics;\n        this.properties = properties;\n\n        this.servoInstanceTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"instance\";\n            }\n\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n\n            @Override\n            public String tagString() {\n                return key.name();\n            }\n\n        };\n        this.servoTypeTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"type\";\n            }\n\n            @Override\n            public String getValue() {\n                return \"HystrixCollapser\";\n            }\n\n            @Override\n            public String tagString() {\n                return \"HystrixCollapser\";\n            }\n\n        };\n    }\n\n    @Override\n    public void initialize() {\n        /* list of monitors */\n        List<Monitor<?>> monitors = getServoMonitors();\n\n        // publish metrics together under a single composite (it seems this name is ignored)\n        MonitorConfig commandMetricsConfig = MonitorConfig.builder(\"HystrixCollapser_\" + key.name()).build();\n        BasicCompositeMonitor commandMetricsMonitor = new BasicCompositeMonitor(commandMetricsConfig, monitors);\n\n        DefaultMonitorRegistry.getInstance().register(commandMetricsMonitor);\n        RollingCollapserBatchSizeDistributionStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCollapserEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        CumulativeCollapserEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n    }\n\n    @Override\n    protected Tag getServoTypeTag() {\n        return servoTypeTag;\n    }\n\n    @Override\n    protected Tag getServoInstanceTag() {\n        return servoInstanceTag;\n    }\n\n    protected Monitor<Number> getCumulativeMonitor(final String name, final HystrixEventType.Collapser event) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                return metrics.getCumulativeCount(event);\n            }\n        };\n    }\n\n    protected Monitor<Number> safelyGetCumulativeMonitor(final String name, final Func0<HystrixEventType.Collapser> eventThunk) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getCumulativeCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n    protected Monitor<Number> getRollingMonitor(final String name, final HystrixEventType.Collapser event) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                return metrics.getRollingCount(event);\n            }\n        };\n    }\n\n    protected Monitor<Number> safelyGetRollingMonitor(final String name, final Func0<HystrixEventType.Collapser> eventThunk) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getRollingCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n    protected Monitor<Number> getBatchSizeMeanMonitor(final String name) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getBatchSizeMean();\n            }\n        };\n    }\n\n    protected Monitor<Number> getBatchSizePercentileMonitor(final String name, final double percentile) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getBatchSizePercentile(percentile);\n            }\n        };\n    }\n\n    protected Monitor<Number> getShardSizeMeanMonitor(final String name) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getShardSizeMean();\n            }\n        };\n    }\n\n    protected Monitor<Number> getShardSizePercentileMonitor(final String name, final double percentile) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getShardSizePercentile(percentile);\n            }\n        };\n    }\n\n    /**\n     * Servo will flatten metric names as: getServoTypeTag()_getServoInstanceTag()_monitorName\n     *\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-servo-metric-publisher,\n     * the code below may reference a HystrixEventType.Collapser that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     */\n    private List<Monitor<?>> getServoMonitors() {\n\n        List<Monitor<?>> monitors = new ArrayList<Monitor<?>>();\n\n        monitors.add(new InformationalMetric<String>(MonitorConfig.builder(\"name\").build()) {\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n        });\n\n        // allow Servo and monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"currentTime\").withTag(DataSourceLevel.DEBUG).build()) {\n            @Override\n            public Number getValue() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        //collapser event cumulative metrics\n        monitors.add(safelyGetCumulativeMonitor(\"countRequestsBatched\", new Func0<HystrixEventType.Collapser>() {\n            @Override\n            public HystrixEventType.Collapser call() {\n                return HystrixEventType.Collapser.ADDED_TO_BATCH;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countBatches\", new Func0<HystrixEventType.Collapser>() {\n            @Override\n            public HystrixEventType.Collapser call() {\n                return HystrixEventType.Collapser.BATCH_EXECUTED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countResponsesFromCache\", new Func0<HystrixEventType.Collapser>() {\n            @Override\n            public HystrixEventType.Collapser call() {\n                return HystrixEventType.Collapser.RESPONSE_FROM_CACHE;\n            }\n        }));\n\n        //batch size distribution metrics\n        monitors.add(getBatchSizeMeanMonitor(\"batchSize_mean\"));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_25\", 25));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_50\", 50));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_75\", 75));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_95\", 95));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_99\", 99));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_99_5\", 99.5));\n        monitors.add(getBatchSizePercentileMonitor(\"batchSize_percentile_100\", 100));\n\n        //shard size distribution metrics\n        monitors.add(getShardSizeMeanMonitor(\"shardSize_mean\"));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_25\", 25));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_50\", 50));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_75\", 75));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_95\", 95));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_99\", 99));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_99_5\", 99.5));\n        monitors.add(getShardSizePercentileMonitor(\"shardSize_percentile_100\", 100));\n\n        // properties (so the values can be inspected and monitored)\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_rollingStatisticalWindowInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_requestCacheEnabled\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_maxRequestsInBatch\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.maxRequestsInBatch().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_timerDelayInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.timerDelayInMilliseconds().get();\n            }\n        });\n\n        return monitors;\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisherCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.consumer.CumulativeCommandEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandLatencyDistributionStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandMaxConcurrencyStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandUserLatencyDistributionStream;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport com.netflix.servo.DefaultMonitorRegistry;\nimport com.netflix.servo.annotations.DataSourceLevel;\nimport com.netflix.servo.monitor.BasicCompositeMonitor;\nimport com.netflix.servo.monitor.Monitor;\nimport com.netflix.servo.monitor.MonitorConfig;\nimport com.netflix.servo.tag.Tag;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Concrete Implementation of {@link HystrixMetricsPublisherCommand} using Servo (https://github.com/Netflix/servo)\n *\n * This class should encapsulate all logic around how to pull metrics.  This will allow any other custom Servo publisher\n * to extend.  Then, if that class wishes to override {@link #initialize()}, that concrete implementation can choose\n * by picking the set of semantic metrics and names, rather than providing an implementation of how.\n */\npublic class HystrixServoMetricsPublisherCommand extends HystrixServoMetricsPublisherAbstract implements HystrixMetricsPublisherCommand {\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixServoMetricsPublisherCommand.class);\n\n    private final HystrixCommandKey key;\n    private final HystrixCommandGroupKey commandGroupKey;\n    private final HystrixCommandMetrics metrics;\n    private final HystrixCircuitBreaker circuitBreaker;\n    private final HystrixCommandProperties properties;\n    private final Tag servoInstanceTag;\n    private final Tag servoTypeTag;\n\n    public HystrixServoMetricsPublisherCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        this.key = commandKey;\n        this.commandGroupKey = commandGroupKey;\n        this.metrics = metrics;\n        this.circuitBreaker = circuitBreaker;\n        this.properties = properties;\n        this.servoInstanceTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"instance\";\n            }\n\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n\n            @Override\n            public String tagString() {\n                return key.name();\n            }\n\n        };\n        this.servoTypeTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"type\";\n            }\n\n            @Override\n            public String getValue() {\n                return \"HystrixCommand\";\n            }\n\n            @Override\n            public String tagString() {\n                return \"HystrixCommand\";\n            }\n\n        };\n    }\n\n    @Override\n    public void initialize() {\n        /* list of monitors */\n        List<Monitor<?>> monitors = getServoMonitors();\n\n        // publish metrics together under a single composite (it seems this name is ignored)\n        MonitorConfig commandMetricsConfig = MonitorConfig.builder(\"HystrixCommand_\" + key.name()).build();\n        BasicCompositeMonitor commandMetricsMonitor = new BasicCompositeMonitor(commandMetricsConfig, monitors);\n\n        DefaultMonitorRegistry.getInstance().register(commandMetricsMonitor);\n        RollingCommandEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        CumulativeCommandEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandLatencyDistributionStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandUserLatencyDistributionStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingCommandMaxConcurrencyStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n    }\n\n    @Override\n    protected Tag getServoTypeTag() {\n        return servoTypeTag;\n    }\n\n    @Override\n    protected Tag getServoInstanceTag() {\n        return servoInstanceTag;\n    }\n\n    protected final Func0<Number> currentConcurrentExecutionCountThunk = new Func0<Number>() {\n        @Override\n        public Integer call() {\n            return metrics.getCurrentConcurrentExecutionCount();\n        }\n    };\n\n    protected final Func0<Number> rollingMaxConcurrentExecutionCountThunk = new Func0<Number>() {\n        @Override\n        public Long call() {\n            return metrics.getRollingMaxConcurrentExecutions();\n        }\n    };\n\n    protected final Func0<Number> errorPercentageThunk = new Func0<Number>() {\n        @Override\n        public Integer call() {\n            return metrics.getHealthCounts().getErrorPercentage();\n        }\n    };\n\n    protected final Func0<Number> currentTimeThunk = new Func0<Number>() {\n        @Override\n        public Number call() {\n            return System.currentTimeMillis();\n        }\n    };\n\n    /**\n     * Convert from HystrixEventType to HystrixRollingNumberEvent\n     * @param eventType HystrixEventType\n     * @return HystrixRollingNumberEvent\n     * @deprecated Instead, use {@link HystrixRollingNumberEvent#from(HystrixEventType)}\n     */\n    @Deprecated\n    protected final HystrixRollingNumberEvent getRollingNumberTypeFromEventType(HystrixEventType eventType) {\n        return HystrixRollingNumberEvent.from(eventType);\n    }\n\n    protected Monitor<Number> getCumulativeMonitor(final String name, final HystrixEventType event) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                return metrics.getCumulativeCount(event);\n            }\n        };\n    }\n\n    protected Monitor<Number> safelyGetCumulativeMonitor(final String name, final Func0<HystrixEventType> eventThunk) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    HystrixEventType eventType = eventThunk.call();\n                    return metrics.getCumulativeCount(HystrixRollingNumberEvent.from(eventType));\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n    protected Monitor<Number> getRollingMonitor(final String name, final HystrixEventType event) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                return metrics.getRollingCount(event);\n            }\n        };\n    }\n\n    protected Monitor<Number> safelyGetRollingMonitor(final String name, final Func0<HystrixEventType> eventThunk) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    HystrixEventType eventType = eventThunk.call();\n                    return metrics.getRollingCount(HystrixRollingNumberEvent.from(eventType));\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n    protected Monitor<Number> getExecutionLatencyMeanMonitor(final String name) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getExecutionTimeMean();\n            }\n        };\n    }\n\n    protected Monitor<Number> getExecutionLatencyPercentileMonitor(final String name, final double percentile) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getExecutionTimePercentile(percentile);\n            }\n        };\n    }\n\n    protected Monitor<Number> getTotalLatencyMeanMonitor(final String name) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getTotalTimeMean();\n            }\n        };\n    }\n\n    protected Monitor<Number> getTotalLatencyPercentileMonitor(final String name, final double percentile) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getTotalTimePercentile(percentile);\n            }\n        };\n    }\n\n    protected Monitor<Number> getCurrentValueMonitor(final String name, final Func0<Number> metricToEvaluate) {\n        return new GaugeMetric(MonitorConfig.builder(name).build()) {\n            @Override\n            public Number getValue() {\n                return metricToEvaluate.call();\n            }\n        };\n    }\n\n    protected Monitor<Number> getCurrentValueMonitor(final String name, final Func0<Number> metricToEvaluate, final Tag tag) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(tag).build()) {\n            @Override\n            public Number getValue() {\n                return metricToEvaluate.call();\n            }\n        };\n    }\n\n    /**\n     * Servo will flatten metric names as: getServoTypeTag()_getServoInstanceTag()_monitorName\n     *\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-servo-metric-publisher,\n     * the code below may reference a HystrixEventType that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     *\n     */\n    private List<Monitor<?>> getServoMonitors() {\n\n        List<Monitor<?>> monitors = new ArrayList<Monitor<?>>();\n\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"isCircuitBreakerOpen\").build()) {\n            @Override\n            public Boolean getValue() {\n                return circuitBreaker.isOpen();\n            }\n        });\n\n        // allow Servo and monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        monitors.add(getCurrentValueMonitor(\"currentTime\", currentTimeThunk, DataSourceLevel.DEBUG));\n\n        // cumulative counts\n        monitors.add(safelyGetCumulativeMonitor(\"countBadRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.BAD_REQUEST;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countCollapsedRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.COLLAPSED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EMIT;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countExceptionsThrown\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EXCEPTION_THROWN;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FAILURE;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFallbackEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_EMIT;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFallbackFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_FAILURE;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFallbackMissing\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_MISSING;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFallbackRejection\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_REJECTION;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countFallbackSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_SUCCESS;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countResponsesFromCache\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.RESPONSE_FROM_CACHE;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countSemaphoreRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SEMAPHORE_REJECTED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countShortCircuited\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SHORT_CIRCUITED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SUCCESS;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countThreadPoolRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.THREAD_POOL_REJECTED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countTimeout\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.TIMEOUT;\n            }\n        }));\n\n        // rolling counts\n        monitors.add(safelyGetRollingMonitor(\"rollingCountBadRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.BAD_REQUEST;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountCollapsedRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.COLLAPSED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EMIT;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountExceptionsThrown\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EXCEPTION_THROWN;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FAILURE;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFallbackEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_EMIT;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFallbackFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_FAILURE;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFallbackMissing\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_MISSING;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFallbackRejection\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_REJECTION;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountFallbackSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_SUCCESS;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountResponsesFromCache\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.RESPONSE_FROM_CACHE;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountSemaphoreRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SEMAPHORE_REJECTED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountShortCircuited\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SHORT_CIRCUITED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SUCCESS;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountThreadPoolRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.THREAD_POOL_REJECTED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountTimeout\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.TIMEOUT;\n            }\n        }));\n\n        // the number of executionSemaphorePermits in use right now\n        monitors.add(getCurrentValueMonitor(\"executionSemaphorePermitsInUse\", currentConcurrentExecutionCountThunk));\n\n        // error percentage derived from current metrics\n        monitors.add(getCurrentValueMonitor(\"errorPercentage\", errorPercentageThunk));\n\n        // execution latency metrics\n        monitors.add(getExecutionLatencyMeanMonitor(\"latencyExecute_mean\"));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_5\", 5));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_25\", 25));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_50\", 50));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_75\", 75));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_90\", 90));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_99\", 99));\n        monitors.add(getExecutionLatencyPercentileMonitor(\"latencyExecute_percentile_995\", 99.5));\n\n        // total latency metrics\n        monitors.add(getTotalLatencyMeanMonitor(\"latencyTotal_mean\"));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_5\", 5));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_25\", 25));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_50\", 50));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_75\", 75));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_90\", 90));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_99\", 99));\n        monitors.add(getTotalLatencyPercentileMonitor(\"latencyTotal_percentile_995\", 99.5));\n\n        // group\n        monitors.add(new InformationalMetric<String>(MonitorConfig.builder(\"commandGroup\").build()) {\n            @Override\n            public String getValue() {\n                return commandGroupKey != null ? commandGroupKey.name() : null;\n            }\n        });\n\n        // properties (so the values can be inspected and monitored)\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_rollingStatisticalWindowInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_circuitBreakerRequestVolumeThreshold\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerRequestVolumeThreshold().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_circuitBreakerSleepWindowInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerSleepWindowInMilliseconds().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_circuitBreakerErrorThresholdPercentage\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.circuitBreakerErrorThresholdPercentage().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_circuitBreakerForceOpen\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.circuitBreakerForceOpen().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_circuitBreakerForceClosed\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.circuitBreakerForceClosed().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_executionTimeoutInMilliseconds\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        monitors.add(new InformationalMetric<String>(MonitorConfig.builder(\"propertyValue_executionIsolationStrategy\").build()) {\n            @Override\n            public String getValue() {\n                return properties.executionIsolationStrategy().get().name();\n            }\n        });\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_metricsRollingPercentileEnabled\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.metricsRollingPercentileEnabled().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_requestCacheEnabled\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Boolean>(MonitorConfig.builder(\"propertyValue_requestLogEnabled\").build()) {\n            @Override\n            public Boolean getValue() {\n                return properties.requestLogEnabled().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.executionIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.fallbackIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n\n        return monitors;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisherThreadPool.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.metric.consumer.CumulativeThreadPoolEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingThreadPoolMaxConcurrencyStream;\nimport com.netflix.hystrix.metric.consumer.RollingThreadPoolEventCounterStream;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\nimport com.netflix.servo.DefaultMonitorRegistry;\nimport com.netflix.servo.annotations.DataSourceLevel;\nimport com.netflix.servo.monitor.BasicCompositeMonitor;\nimport com.netflix.servo.monitor.Monitor;\nimport com.netflix.servo.monitor.MonitorConfig;\nimport com.netflix.servo.tag.Tag;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherThreadPool} using Servo (https://github.com/Netflix/servo)\n */\npublic class HystrixServoMetricsPublisherThreadPool extends HystrixServoMetricsPublisherAbstract implements HystrixMetricsPublisherThreadPool {\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixServoMetricsPublisherThreadPool.class);\n\n    private final HystrixThreadPoolKey key;\n    private final HystrixThreadPoolMetrics metrics;\n    private final HystrixThreadPoolProperties properties;\n    private final Tag servoInstanceTag;\n    private final Tag servoTypeTag;\n\n    public HystrixServoMetricsPublisherThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        this.key = threadPoolKey;\n        this.metrics = metrics;\n        this.properties = properties;\n\n        this.servoInstanceTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"instance\";\n            }\n\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n\n            @Override\n            public String tagString() {\n                return key.name();\n            }\n\n        };\n        this.servoTypeTag = new Tag() {\n\n            @Override\n            public String getKey() {\n                return \"type\";\n            }\n\n            @Override\n            public String getValue() {\n                return \"HystrixThreadPool\";\n            }\n\n            @Override\n            public String tagString() {\n                return \"HystrixThreadPool\";\n            }\n\n        };\n    }\n\n    @Override\n    public void initialize() {\n        /* list of monitors */\n        List<Monitor<?>> monitors = getServoMonitors();\n\n        // publish metrics together under a single composite (it seems this name is ignored)\n        MonitorConfig commandMetricsConfig = MonitorConfig.builder(\"HystrixThreadPool_\" + key.name()).build();\n        BasicCompositeMonitor commandMetricsMonitor = new BasicCompositeMonitor(commandMetricsConfig, monitors);\n\n        DefaultMonitorRegistry.getInstance().register(commandMetricsMonitor);\n        RollingThreadPoolEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        CumulativeThreadPoolEventCounterStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n        RollingThreadPoolMaxConcurrencyStream.getInstance(key, properties).startCachingStreamValuesIfUnstarted();\n    }\n\n    @Override\n    protected Tag getServoTypeTag() {\n        return servoTypeTag;\n    }\n\n    @Override\n    protected Tag getServoInstanceTag() {\n        return servoInstanceTag;\n    }\n\n    protected Monitor<Number> safelyGetCumulativeMonitor(final String name, final Func0<HystrixEventType.ThreadPool> eventThunk) {\n        return new CounterMetric(MonitorConfig.builder(name).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getCumulativeCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n\n    protected Monitor<Number> safelyGetRollingMonitor(final String name, final Func0<HystrixEventType.ThreadPool> eventThunk) {\n        return new GaugeMetric(MonitorConfig.builder(name).withTag(DataSourceLevel.DEBUG).withTag(getServoTypeTag()).withTag(getServoInstanceTag()).build()) {\n            @Override\n            public Long getValue() {\n                try {\n                    return metrics.getRollingCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Servo metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        };\n    }\n\n    /**\n     * Servo will flatten metric names as: getServoTypeTag()_getServoInstanceTag()_monitorName\n     *\n     * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-servo-metric-publisher,\n     * the code below may reference a HystrixEventType.ThreadPool that does not exist in hystrix-core.  If this happens,\n     * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n     * and we should log an error to get users to update their dependency set.\n     */\n    private List<Monitor<?>> getServoMonitors() {\n\n        List<Monitor<?>> monitors = new ArrayList<Monitor<?>>();\n\n        monitors.add(new InformationalMetric<String>(MonitorConfig.builder(\"name\").build()) {\n            @Override\n            public String getValue() {\n                return key.name();\n            }\n        });\n\n        // allow Servo and monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"currentTime\").withTag(DataSourceLevel.DEBUG).build()) {\n            @Override\n            public Number getValue() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"threadActiveCount\").build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentActiveCount();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"completedTaskCount\").build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentCompletedTaskCount();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"largestPoolSize\").build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentLargestPoolSize();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"totalTaskCount\").build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentTaskCount();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"queueSize\").build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getCurrentQueueSize();\n            }\n        });\n\n        monitors.add(new GaugeMetric(MonitorConfig.builder(\"rollingMaxActiveThreads\").withTag(DataSourceLevel.DEBUG).build()) {\n            @Override\n            public Number getValue() {\n                return metrics.getRollingMaxActiveThreads();\n            }\n        });\n\n        //thread pool event monitors\n        monitors.add(safelyGetCumulativeMonitor(\"countThreadsExecuted\", new Func0<HystrixEventType.ThreadPool>() {\n            @Override\n            public HystrixEventType.ThreadPool call() {\n                return HystrixEventType.ThreadPool.EXECUTED;\n            }\n        }));\n        monitors.add(safelyGetCumulativeMonitor(\"countThreadsRejected\", new Func0<HystrixEventType.ThreadPool>() {\n            @Override\n            public HystrixEventType.ThreadPool call() {\n                return HystrixEventType.ThreadPool.REJECTED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountThreadsExecuted\", new Func0<HystrixEventType.ThreadPool>() {\n            @Override\n            public HystrixEventType.ThreadPool call() {\n                return HystrixEventType.ThreadPool.EXECUTED;\n            }\n        }));\n        monitors.add(safelyGetRollingMonitor(\"rollingCountCommandsRejected\", new Func0<HystrixEventType.ThreadPool>() {\n            @Override\n            public HystrixEventType.ThreadPool call() {\n                return HystrixEventType.ThreadPool.REJECTED;\n            }\n        }));\n\n        // properties\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_corePoolSize\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.coreSize().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_maximumSize\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.maximumSize().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_actualMaximumSize\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.actualMaximumSize();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_keepAliveTimeInMinutes\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.keepAliveTimeMinutes().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_queueSizeRejectionThreshold\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.queueSizeRejectionThreshold().get();\n            }\n        });\n\n        monitors.add(new InformationalMetric<Number>(MonitorConfig.builder(\"propertyValue_maxQueueSize\").build()) {\n            @Override\n            public Number getValue() {\n                return properties.maxQueueSize().get();\n            }\n        });\n\n        return monitors;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-servo-metrics-publisher/src/test/java/com/netflix/hystrix/contrib/servopublisher/HystrixServoMetricsPublisherCommandTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.servopublisher;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesCommandDefault;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.observers.TestSubscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\npublic class HystrixServoMetricsPublisherCommandTest {\n\n    private static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ServoGROUP\");\n    private static HystrixCommandProperties.Setter propertiesSetter = HystrixCommandProperties.Setter()\n            .withCircuitBreakerEnabled(true)\n            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)\n            .withExecutionTimeoutInMilliseconds(100)\n            .withMetricsRollingStatisticalWindowInMilliseconds(1000)\n            .withMetricsRollingPercentileWindowInMilliseconds(1000)\n            .withMetricsRollingPercentileWindowBuckets(10);\n\n\n\t@Test\n\tpublic void testCumulativeCounters() throws Exception {\n\t\t//execute 10 commands/sec (8 SUCCESS, 1 FAILURE, 1 TIMEOUT).\n\t\t//after 5 seconds, cumulative counters should have observed 50 commands (40 SUCCESS, 5 FAILURE, 5 TIMEOUT)\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"ServoCOMMAND-A\");\n        HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);\n        HystrixCommandProperties properties = new HystrixPropertiesCommandDefault(key, propertiesSetter);\n        HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(key, groupKey, properties);\n        HystrixServoMetricsPublisherCommand servoPublisher = new HystrixServoMetricsPublisherCommand(key, groupKey, metrics, circuitBreaker, properties);\n        servoPublisher.initialize();\n\n        final int NUM_SECONDS = 5;\n\n        for (int i = 0; i < NUM_SECONDS; i++) {\n            new SuccessCommand(key).execute();\n            new SuccessCommand(key).execute();\n            new SuccessCommand(key).execute();\n            Thread.sleep(10);\n            new TimeoutCommand(key).execute();\n            new SuccessCommand(key).execute();\n            new FailureCommand(key).execute();\n            new SuccessCommand(key).execute();\n            new SuccessCommand(key).execute();\n            new SuccessCommand(key).execute();\n            Thread.sleep(10);\n            new SuccessCommand(key).execute();\n        }\n\n        Thread.sleep(500);\n\n        assertEquals(40L, servoPublisher.getCumulativeMonitor(\"success\", HystrixEventType.SUCCESS).getValue());\n        assertEquals(5L, servoPublisher.getCumulativeMonitor(\"timeout\", HystrixEventType.TIMEOUT).getValue());\n        assertEquals(5L, servoPublisher.getCumulativeMonitor(\"failure\", HystrixEventType.FAILURE).getValue());\n        assertEquals(10L, servoPublisher.getCumulativeMonitor(\"fallback_success\", HystrixEventType.FALLBACK_SUCCESS).getValue());\n\t}\n\n    @Test\n    public void testRollingCounters() throws Exception {\n        //execute 10 commands, then sleep for 2000ms to let these age out\n        //execute 10 commands again, these should show up in rolling count\n\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"ServoCOMMAND-B\");\n        HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);\n        HystrixCommandProperties properties = new HystrixPropertiesCommandDefault(key, propertiesSetter);\n        HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(key, groupKey, properties);\n        HystrixServoMetricsPublisherCommand servoPublisher = new HystrixServoMetricsPublisherCommand(key, groupKey, metrics, circuitBreaker, properties);\n        servoPublisher.initialize();\n\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new TimeoutCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new FailureCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n\n        Thread.sleep(2000);\n\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new TimeoutCommand(key).execute();\n        new SuccessCommand(key).execute();\n        new FailureCommand(key).execute();\n        new TimeoutCommand(key).execute();\n        new TimeoutCommand(key).execute();\n        new TimeoutCommand(key).execute();\n        new TimeoutCommand(key).execute();\n\n        Thread.sleep(100); //time for 1 bucket roll\n\n        assertEquals(4L, servoPublisher.getRollingMonitor(\"success\", HystrixEventType.SUCCESS).getValue());\n        assertEquals(5L, servoPublisher.getRollingMonitor(\"timeout\", HystrixEventType.TIMEOUT).getValue());\n        assertEquals(1L, servoPublisher.getRollingMonitor(\"failure\", HystrixEventType.FAILURE).getValue());\n        assertEquals(6L, servoPublisher.getRollingMonitor(\"falback_success\", HystrixEventType.FALLBACK_SUCCESS).getValue());\n    }\n\n    @Test\n    public void testRollingLatencies() throws Exception {\n        //execute 10 commands, then sleep for 2000ms to let these age out\n        //execute 10 commands again, these should show up in rolling count\n\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"ServoCOMMAND-C\");\n        HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);\n        HystrixCommandProperties properties = new HystrixPropertiesCommandDefault(key, propertiesSetter);\n        HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(key, groupKey, properties);\n\n        HystrixServoMetricsPublisherCommand servoPublisher = new HystrixServoMetricsPublisherCommand(key, groupKey, metrics, circuitBreaker, properties);\n        servoPublisher.initialize();\n\n        new SuccessCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n        new TimeoutCommand(key).execute();\n        new SuccessCommand(key, 5).execute();\n        new FailureCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n        new SuccessCommand(key, 5).execute();\n\n        Thread.sleep(2000);\n\n        List<Observable<Integer>> os = new ArrayList<Observable<Integer>>();\n        TestSubscriber<Integer> testSubscriber = new TestSubscriber<Integer>();\n\n        os.add(new SuccessCommand(key, 10).observe());\n        os.add(new SuccessCommand(key, 20).observe());\n        os.add(new SuccessCommand(key, 10).observe());\n        os.add(new TimeoutCommand(key).observe());\n        os.add(new SuccessCommand(key, 15).observe());\n        os.add(new FailureCommand(key, 10).observe());\n        os.add(new TimeoutCommand(key).observe());\n        os.add(new TimeoutCommand(key).observe());\n        os.add(new TimeoutCommand(key).observe());\n        os.add(new TimeoutCommand(key).observe());\n\n        Observable.merge(os).subscribe(testSubscriber);\n\n        testSubscriber.awaitTerminalEvent(300, TimeUnit.MILLISECONDS);\n        testSubscriber.assertCompleted();\n        testSubscriber.assertNoErrors();\n\n        Thread.sleep(100); //1 bucket roll\n\n        int meanExecutionLatency = servoPublisher.getExecutionLatencyMeanMonitor(\"meanExecutionLatency\").getValue().intValue();\n        int p5ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p5ExecutionLatency\", 5).getValue().intValue();\n        int p25ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p25ExecutionLatency\", 25).getValue().intValue();\n        int p50ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p50ExecutionLatency\", 50).getValue().intValue();\n        int p75ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p75ExecutionLatency\", 75).getValue().intValue();\n        int p90ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p90ExecutionLatency\", 90).getValue().intValue();\n        int p99ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p99ExecutionLatency\", 99).getValue().intValue();\n        int p995ExecutionLatency = servoPublisher.getExecutionLatencyPercentileMonitor(\"p995ExecutionLatency\", 99.5).getValue().intValue();\n        System.out.println(\"Execution:           Mean : \" + meanExecutionLatency + \", p5 : \" + p5ExecutionLatency + \", p25 : \" + p25ExecutionLatency + \", p50 : \" + p50ExecutionLatency + \", p75 : \" + p75ExecutionLatency + \", p90 : \" + p90ExecutionLatency + \", p99 : \" + p99ExecutionLatency + \", p99.5 : \" + p995ExecutionLatency);\n\n        int meanTotalLatency = servoPublisher.getTotalLatencyMeanMonitor(\"meanTotalLatency\").getValue().intValue();\n        int p5TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p5TotalLatency\", 5).getValue().intValue();\n        int p25TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p25TotalLatency\", 25).getValue().intValue();\n        int p50TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p50TotalLatency\", 50).getValue().intValue();\n        int p75TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p75TotalLatency\", 75).getValue().intValue();\n        int p90TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p90TotalLatency\", 90).getValue().intValue();\n        int p99TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p99TotalLatency\", 99).getValue().intValue();\n        int p995TotalLatency = servoPublisher.getTotalLatencyPercentileMonitor(\"p995TotalLatency\", 99.5).getValue().intValue();\n        System.out.println(\"Total:           Mean : \" + meanTotalLatency + \", p5 : \" + p5TotalLatency + \", p25 : \" + p25TotalLatency + \", p50 : \" + p50TotalLatency + \", p75 : \" + p75TotalLatency + \", p90 : \" + p90TotalLatency + \", p99 : \" + p99TotalLatency + \", p99.5 : \" + p995TotalLatency);\n\n\n        assertTrue(meanExecutionLatency > 10);\n        assertTrue(p5ExecutionLatency <= p25ExecutionLatency);\n        assertTrue(p25ExecutionLatency <= p50ExecutionLatency);\n        assertTrue(p50ExecutionLatency <= p75ExecutionLatency);\n        assertTrue(p75ExecutionLatency <= p90ExecutionLatency);\n        assertTrue(p90ExecutionLatency <= p99ExecutionLatency);\n        assertTrue(p99ExecutionLatency <= p995ExecutionLatency);\n\n        assertTrue(meanTotalLatency > 10);\n        assertTrue(p5TotalLatency <= p25TotalLatency);\n        assertTrue(p25TotalLatency <= p50TotalLatency);\n        assertTrue(p50TotalLatency <= p75TotalLatency);\n        assertTrue(p75TotalLatency <= p90TotalLatency);\n        assertTrue(p90TotalLatency <= p99TotalLatency);\n        assertTrue(p99TotalLatency <= p995TotalLatency);\n\n        assertTrue(meanExecutionLatency <= meanTotalLatency);\n        assertTrue(p5ExecutionLatency <= p5TotalLatency);\n        assertTrue(p25ExecutionLatency <= p25TotalLatency);\n        assertTrue(p50ExecutionLatency <= p50TotalLatency);\n        assertTrue(p75ExecutionLatency <= p75TotalLatency);\n        assertTrue(p90ExecutionLatency <= p90TotalLatency);\n        assertTrue(p99ExecutionLatency <= p99TotalLatency);\n        assertTrue(p995ExecutionLatency <= p995TotalLatency);\n    }\n\n    static class SampleCommand extends HystrixCommand<Integer> {\n        boolean shouldFail;\n        int latencyToAdd;\n\n        protected SampleCommand(HystrixCommandKey key, boolean shouldFail, int latencyToAdd) {\n            super(Setter.withGroupKey(groupKey).andCommandKey(key).andCommandPropertiesDefaults(propertiesSetter));\n            this.shouldFail = shouldFail;\n            this.latencyToAdd = latencyToAdd;\n        }\n\n        @Override\n        protected Integer run() throws Exception {\n            if (shouldFail) {\n                throw new RuntimeException(\"command failure\");\n            } else {\n                Thread.sleep(latencyToAdd);\n                return 1;\n            }\n        }\n\n        @Override\n        protected Integer getFallback() {\n            return 99;\n        }\n    }\n\n    static class SuccessCommand extends SampleCommand {\n        protected SuccessCommand(HystrixCommandKey key) {\n            super(key, false, 0);\n        }\n\n        public SuccessCommand(HystrixCommandKey key, int latencyToAdd) {\n            super(key, false, latencyToAdd);\n        }\n    }\n\n    static class FailureCommand extends SampleCommand {\n        protected FailureCommand(HystrixCommandKey key) {\n            super(key, true, 0);\n        }\n\n        public FailureCommand(HystrixCommandKey key, int latencyToAdd) {\n            super(key, true, latencyToAdd);\n        }\n    }\n\n    static class TimeoutCommand extends SampleCommand {\n        protected TimeoutCommand(HystrixCommandKey key) {\n            super(key, false, 400); //exceeds 100ms timeout\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/README.md",
    "content": "# hystrix-yammer-metrics-publisher\n\nThis is an implementation of [HystrixMetricsPublisher](http://netflix.github.com/Hystrix/javadoc/index.html?com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisher.html) that publishes metrics using [Yammer Metrics](http://metrics.codahale.com) version 2. If you are using Coda Hale Metrics version 3, please use the [hystrix-codahale-metrics-publisher](../hystrix-codahale-metrics-publisher) module instead.\n\nSee the [Metrics & Monitoring](https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring) Wiki for more information.\n\n# Binaries\n\nBinaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22hystrix-yammer-metrics-publisher%22).\n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-yammer-metrics-publisher</artifactId>\n    <version>1.1.2</version>\n</dependency>\n```\n\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-yammer-metrics-publisher\" rev=\"1.1.2\" />\n```"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n    api 'com.yammer.metrics:metrics-core:2.2.0'\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/yammermetricspublisher/HystrixYammerMetricsPublisher.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.yammermetricspublisher;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\nimport com.yammer.metrics.Metrics;\nimport com.yammer.metrics.core.MetricsRegistry;\n\n/**\n * Yammer Metrics (https://github.com/codahale/metrics) implementation of {@link HystrixMetricsPublisher}.\n */\npublic class HystrixYammerMetricsPublisher extends HystrixMetricsPublisher {\n    private final MetricsRegistry metricsRegistry;\n\n    public HystrixYammerMetricsPublisher() {\n        this(Metrics.defaultRegistry());\n    }\n\n    public HystrixYammerMetricsPublisher(MetricsRegistry metricsRegistry) {\n        this.metricsRegistry = metricsRegistry;\n    }\n\n    @Override\n    public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        return new HystrixYammerMetricsPublisherCommand(commandKey, commandGroupKey, metrics, circuitBreaker, properties, metricsRegistry);\n    }\n\n    @Override\n    public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        return new HystrixYammerMetricsPublisherThreadPool(threadPoolKey, metrics, properties, metricsRegistry);\n    }\n\n    @Override\n    public HystrixMetricsPublisherCollapser getMetricsPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        return new HystrixYammerMetricsPublisherCollapser(collapserKey, metrics, properties, metricsRegistry);\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/yammermetricspublisher/HystrixYammerMetricsPublisherCollapser.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.yammermetricspublisher;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCollapser;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport com.yammer.metrics.core.Gauge;\nimport com.yammer.metrics.core.MetricName;\nimport com.yammer.metrics.core.MetricsRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherCollapser} using Yammer Metrics\n *\n *\n * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-yammer-metrics-publisher,\n * the code below may reference a HystrixRollingNumberEvent that does not exist in hystrix-core.  If this happens,\n * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n * and we should log an error to get users to update their dependency set.\n */\npublic class HystrixYammerMetricsPublisherCollapser implements HystrixMetricsPublisherCollapser {\n    private final HystrixCollapserKey key;\n    private final HystrixCollapserMetrics metrics;\n    private final HystrixCollapserProperties properties;\n    private final MetricsRegistry metricsRegistry;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixYammerMetricsPublisherCollapser.class);\n\n    public HystrixYammerMetricsPublisherCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties, MetricsRegistry metricsRegistry) {\n        this.key = collapserKey;\n        this.metrics = metrics;\n        this.properties = properties;\n        this.metricsRegistry = metricsRegistry;\n        this.metricType = key.name();\n    }\n\n    @Override\n    public void initialize() {\n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricsRegistry.newGauge(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        // cumulative counts\n        safelyCreateCumulativeCountForEvent(\"countRequestsBatched\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_REQUEST_BATCHED;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countBatches\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_BATCH;\n            }\n        });\n        safelyCreateCumulativeCountForEvent(\"countResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n\n        // rolling counts\n        safelyCreateRollingCountForEvent(\"rollingRequestsBatched\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_REQUEST_BATCHED;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingBatches\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.COLLAPSER_BATCH;\n            }\n        });\n        safelyCreateRollingCountForEvent(\"rollingCountResponsesFromCache\", new Func0<HystrixRollingNumberEvent>() {\n            @Override\n            public HystrixRollingNumberEvent call() {\n                return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            }\n        });\n\n        // batch size metrics\n        metricsRegistry.newGauge(createMetricName(\"batchSize_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizeMean();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(25);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(50);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(75);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(90);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(99);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"batchSize_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getBatchSizePercentile(99.5);\n            }\n        });\n\n        // shard size metrics\n        metricsRegistry.newGauge(createMetricName(\"shardSize_mean\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizeMean();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_25\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(25);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_50\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(50);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_75\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(75);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_90\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(90);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_99\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(99);\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"shardSize_percentile_995\"), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getShardSizePercentile(99.5);\n            }\n        });\n\n        // properties (so the values can be inspected and monitored)\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_rollingStatisticalWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_requestCacheEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_maxRequestsInBatch\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.maxRequestsInBatch().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_timerDelayInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.timerDelayInMilliseconds().get();\n            }\n        });\n    }\n\n    protected MetricName createMetricName(String name) {\n        return new MetricName(\"\", metricType, name);\n    }\n\n    protected void createCumulativeCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getCumulativeCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateCumulativeCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                try {\n                    return metrics.getCumulativeCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Yammer metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n\n    protected void createRollingCountForEvent(final String name, final HystrixRollingNumberEvent event) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getRollingCount(event);\n            }\n        });\n    }\n\n    protected void safelyCreateRollingCountForEvent(final String name, final Func0<HystrixRollingNumberEvent> eventThunk) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                try {\n                    return metrics.getRollingCount(eventThunk.call());\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Yammer metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/yammermetricspublisher/HystrixYammerMetricsPublisherCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.yammermetricspublisher;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport com.yammer.metrics.core.Gauge;\nimport com.yammer.metrics.core.MetricName;\nimport com.yammer.metrics.core.MetricsRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherCommand} using Yammer Metrics (https://github.com/codahale/metrics)\n *\n * An implementation note.  If there's a version mismatch between hystrix-core and hystrix-yammer-metrics-publisher,\n * the code below may reference a HystrixRollingNumberEvent that does not exist in hystrix-core.  If this happens,\n * a j.l.NoSuchFieldError occurs.  Since this data is not being generated by hystrix-core, it's safe to count it as 0\n * and we should log an error to get users to update their dependency set.\n\n */\npublic class HystrixYammerMetricsPublisherCommand implements HystrixMetricsPublisherCommand {\n    private final HystrixCommandKey key;\n    private final HystrixCommandGroupKey commandGroupKey;\n    private final HystrixCommandMetrics metrics;\n    private final HystrixCircuitBreaker circuitBreaker;\n    private final HystrixCommandProperties properties;\n    private final MetricsRegistry metricsRegistry;\n    private final String metricGroup;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixYammerMetricsPublisherCommand.class);\n\n    public HystrixYammerMetricsPublisherCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties, MetricsRegistry metricsRegistry) {\n        this.key = commandKey;\n        this.commandGroupKey = commandGroupKey;\n        this.metrics = metrics;\n        this.circuitBreaker = circuitBreaker;\n        this.properties = properties;\n        this.metricsRegistry = metricsRegistry;\n        this.metricGroup = \"HystrixCommand\";\n        this.metricType = key.name();\n    }\n\n    @Override\n    public void initialize() {\n        metricsRegistry.newGauge(createMetricName(\"isCircuitBreakerOpen\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return circuitBreaker.isOpen();\n            }\n        });\n\n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricsRegistry.newGauge(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        // cumulative counts\n        safelyCreateCumulativeGauge(\"countBadRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.BAD_REQUEST;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countCollapsedRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.COLLAPSED;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EMIT;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countExceptionsThrown\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EXCEPTION_THROWN;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FAILURE;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFallbackEmit\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_EMIT;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFallbackFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_FAILURE;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFallbackMissing\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_MISSING;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFallbackRejection\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_REJECTION;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countFallbackSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_SUCCESS;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countResponsesFromCache\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.RESPONSE_FROM_CACHE;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countSemaphoreRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SEMAPHORE_REJECTED;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countShortCircuited\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SHORT_CIRCUITED;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SUCCESS;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countThreadPoolRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.THREAD_POOL_REJECTED;\n            }\n        });\n        safelyCreateCumulativeGauge(\"countTimeout\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.TIMEOUT;\n            }\n        });\n\n        // rolling counts\n        safelyCreateRollingGauge(\"rollingCountBadRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.BAD_REQUEST;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountCollapsedRequests\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.COLLAPSED;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountExceptionsThrown\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.EXCEPTION_THROWN;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FAILURE;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountFallbackFailure\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_FAILURE;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountFallbackMissing\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_MISSING;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountFallbackRejection\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_REJECTION;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountFallbackSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.FALLBACK_SUCCESS;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountResponsesFromCache\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.RESPONSE_FROM_CACHE;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountSemaphoreRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SEMAPHORE_REJECTED;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountShortCircuited\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SHORT_CIRCUITED;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountSuccess\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.SUCCESS;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountThreadPoolRejected\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.THREAD_POOL_REJECTED;\n            }\n        });\n        safelyCreateRollingGauge(\"rollingCountTimeout\", new Func0<HystrixEventType>() {\n            @Override\n            public HystrixEventType call() {\n                return HystrixEventType.TIMEOUT;\n            }\n        });\n\n        // the number of executionSemaphorePermits in use right now \n        createCurrentValueGauge(\"executionSemaphorePermitsInUse\", currentConcurrentExecutionCountThunk);\n\n        // error percentage derived from current metrics \n        createCurrentValueGauge(\"errorPercentage\", errorPercentageThunk);\n\n        // latency metrics\n        createExecutionLatencyMeanGauge(\"latencyExecute_mean\");\n\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_5\", 5);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_25\", 25);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_50\", 50);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_75\", 75);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_90\", 90);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_99\", 99);\n        createExecutionLatencyPercentileGauge(\"latencyExecute_percentile_995\", 99.5);\n\n        createTotalLatencyMeanGauge(\"latencyTotal_mean\");\n\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_5\", 5);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_25\", 25);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_50\", 50);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_75\", 75);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_90\", 90);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_99\", 99);\n        createTotalLatencyPercentileGauge(\"latencyTotal_percentile_995\", 99.5);\n\n        // group\n        metricsRegistry.newGauge(createMetricName(\"commandGroup\"), new Gauge<String>() {\n            @Override\n            public String value() {\n                return commandGroupKey != null ? commandGroupKey.name() : null;\n            }\n        });\n\n        // properties (so the values can be inspected and monitored)\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_rollingStatisticalWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.metricsRollingStatisticalWindowInMilliseconds().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_circuitBreakerRequestVolumeThreshold\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.circuitBreakerRequestVolumeThreshold().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_circuitBreakerSleepWindowInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.circuitBreakerSleepWindowInMilliseconds().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_circuitBreakerErrorThresholdPercentage\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.circuitBreakerErrorThresholdPercentage().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_circuitBreakerForceOpen\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.circuitBreakerForceOpen().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_circuitBreakerForceClosed\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.circuitBreakerForceClosed().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_executionTimeoutInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.executionTimeoutInMilliseconds().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_executionIsolationStrategy\"), new Gauge<String>() {\n            @Override\n            public String value() {\n                return properties.executionIsolationStrategy().get().name();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_metricsRollingPercentileEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.metricsRollingPercentileEnabled().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_requestCacheEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.requestCacheEnabled().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_requestLogEnabled\"), new Gauge<Boolean>() {\n            @Override\n            public Boolean value() {\n                return properties.requestLogEnabled().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.executionIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.fallbackIsolationSemaphoreMaxConcurrentRequests().get();\n            }\n        });\n    }\n\n    protected MetricName createMetricName(String name) {\n        return new MetricName(metricGroup, metricType, name);\n    }\n\n    @Deprecated\n    protected void createCumulativeCountForEvent(String name, final HystrixRollingNumberEvent event) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getCumulativeCount(event);\n            }\n        });\n    }\n\n    protected void createCumulativeGauge(final String name, final HystrixEventType eventType) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getCumulativeCount(HystrixRollingNumberEvent.from(eventType));\n            }\n        });\n    }\n\n    protected void safelyCreateCumulativeGauge(final String name, final Func0<HystrixEventType> eventThunk) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                try {\n                    HystrixRollingNumberEvent eventType = HystrixRollingNumberEvent.from(eventThunk.call());\n                    return metrics.getCumulativeCount(eventType);\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Yammer metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n\n    @Deprecated\n    protected void createRollingGauge(String name, final HystrixRollingNumberEvent event) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getRollingCount(event);\n            }\n        });\n    }\n\n    protected void createRollingGauge(final String name, final HystrixEventType eventType) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return metrics.getRollingCount(HystrixRollingNumberEvent.from(eventType));\n            }\n        });\n    }\n\n    protected void safelyCreateRollingGauge(final String name, final Func0<HystrixEventType> eventThunk) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                try {\n                    HystrixRollingNumberEvent eventType = HystrixRollingNumberEvent.from(eventThunk.call());\n                    return metrics.getRollingCount(eventType);\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Yammer metrics, error looking up eventType for : {}.  Please check that all Hystrix versions are the same!\", name);\n                    return 0L;\n                }\n            }\n        });\n    }\n\n    protected void createExecutionLatencyMeanGauge(final String name) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getExecutionTimeMean();\n            }\n        });\n    }\n\n    protected void createExecutionLatencyPercentileGauge(final String name, final double percentile) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getExecutionTimePercentile(percentile);\n            }\n        });\n    }\n\n    protected void createTotalLatencyMeanGauge(final String name) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getTotalTimeMean();\n            }\n        });\n    }\n\n    protected void createTotalLatencyPercentileGauge(final String name, final double percentile) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metrics.getTotalTimePercentile(percentile);\n            }\n        });\n    }\n\n    protected final Func0<Integer> currentConcurrentExecutionCountThunk = new Func0<Integer>() {\n        @Override\n        public Integer call() {\n            return metrics.getCurrentConcurrentExecutionCount();\n        }\n    };\n\n    protected final Func0<Long> rollingMaxConcurrentExecutionCountThunk = new Func0<Long>() {\n        @Override\n        public Long call() {\n            return metrics.getRollingMaxConcurrentExecutions();\n        }\n    };\n\n    protected final Func0<Integer> errorPercentageThunk = new Func0<Integer>() {\n        @Override\n        public Integer call() {\n            return metrics.getHealthCounts().getErrorPercentage();\n        }\n    };\n\n    protected void createCurrentValueGauge(final String name, final Func0<Integer> metricToEvaluate) {\n        metricsRegistry.newGauge(createMetricName(name), new Gauge<Integer>() {\n            @Override\n            public Integer value() {\n                return metricToEvaluate.call();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "hystrix-contrib/hystrix-yammer-metrics-publisher/src/main/java/com/netflix/hystrix/contrib/yammermetricspublisher/HystrixYammerMetricsPublisherThreadPool.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.contrib.yammermetricspublisher;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport com.yammer.metrics.core.Gauge;\nimport com.yammer.metrics.core.MetricName;\nimport com.yammer.metrics.core.MetricsRegistry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Implementation of {@link HystrixMetricsPublisherThreadPool} using Yammer Metrics (https://github.com/codahale/metrics)\n */\npublic class HystrixYammerMetricsPublisherThreadPool implements HystrixMetricsPublisherThreadPool {\n    private final HystrixThreadPoolKey key;\n    private final HystrixThreadPoolMetrics metrics;\n    private final HystrixThreadPoolProperties properties;\n    private final MetricsRegistry metricsRegistry;\n    private final String metricGroup;\n    private final String metricType;\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixYammerMetricsPublisherThreadPool.class);\n\n\n    public HystrixYammerMetricsPublisherThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties, MetricsRegistry metricsRegistry) {\n        this.key = threadPoolKey;\n        this.metrics = metrics;\n        this.properties = properties;\n        this.metricsRegistry = metricsRegistry;\n        this.metricGroup = \"HystrixThreadPool\";\n        this.metricType = key.name();\n    }\n\n    @Override\n    public void initialize() {\n        metricsRegistry.newGauge(createMetricName(\"name\"), new Gauge<String>() {\n            @Override\n            public String value() {\n                return key.name();\n            }\n        });\n        \n        // allow monitor to know exactly at what point in time these stats are for so they can be plotted accurately\n        metricsRegistry.newGauge(createMetricName(\"currentTime\"), new Gauge<Long>() {\n            @Override\n            public Long value() {\n                return System.currentTimeMillis();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"threadActiveCount\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCurrentActiveCount();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"completedTaskCount\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCurrentCompletedTaskCount();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"largestPoolSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCurrentLargestPoolSize();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"totalTaskCount\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCurrentTaskCount();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"queueSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCurrentQueueSize();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"rollingMaxActiveThreads\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getRollingMaxActiveThreads();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"countThreadsExecuted\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getCumulativeCountThreadsExecuted();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"rollingCountCommandsRejected\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                try {\n                    return metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED);\n                } catch (NoSuchFieldError error) {\n                    logger.error(\"While publishing Yammer metrics, error looking up eventType for : rollingCountCommandsRejected.  Please check that all Hystrix versions are the same!\");\n                    return 0L;\n                }\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"rollingCountThreadsExecuted\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return metrics.getRollingCountThreadsExecuted();\n            }\n        });\n\n        // properties\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_corePoolSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.coreSize().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_maximumSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.maximumSize().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_actualMaximumSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.actualMaximumSize();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_keepAliveTimeInMinutes\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.keepAliveTimeMinutes().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_queueSizeRejectionThreshold\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.queueSizeRejectionThreshold().get();\n            }\n        });\n\n        metricsRegistry.newGauge(createMetricName(\"propertyValue_maxQueueSize\"), new Gauge<Number>() {\n            @Override\n            public Number value() {\n                return properties.maxQueueSize().get();\n            }\n        });\n    }\n\n    protected MetricName createMetricName(String name) {\n        return new MetricName(metricGroup, metricType, name);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/README.md",
    "content": "## hystrix-core\n\nThis is the core module of Hystrix.\n\nKey classes you're most likely to interact with are:\n\n- HystrixCommand [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html)\n- HystrixObservableCommand [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixObservableCommand.html)\n- HystrixCollapser [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapser.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixCollapser.html)\n- HystrixRequestLog [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/HystrixRequestLog.html)\n- HystrixPlugins [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/strategy/HystrixPlugins.html)\n- HystrixRequestContext [Source](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestContext.java) [Javadoc](http://netflix.github.com/Hystrix/javadoc/com/netflix/hystrix/strategy/concurrency/HystrixRequestContext.html)\n\n## Documentation\n\nA general project README can be found at the [project home](https://github.com/Netflix/Hystrix).\n\nThe [Wiki](https://github.com/Netflix/Hystrix/wiki) contains detailed documentation.\n\n\n## Maven Central\n\nBinaries and dependencies for this module can be found on [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20a%3A%22hystrix-core%22).\n\n__GroupId: com.netflix.hystrix__  \n__ArtifactId: hystrix-core__  \n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-core</artifactId>\n    <version>1.2.0</version>\n</dependency>\n```\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-core\" rev=\"1.2.0\" />\n```\n"
  },
  {
    "path": "hystrix-core/build.gradle",
    "content": "apply plugin: 'me.champeau.jmh'\n\ndependencies {\n    api 'com.netflix.archaius:archaius-core:0.4.1'\n    api 'io.reactivex:rxjava:1.2.0'\n    implementation 'org.slf4j:slf4j-api:1.7.0'\n    api 'org.hdrhistogram:HdrHistogram:2.1.9'\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation project(':hystrix-junit')\n}\n\n\njavadoc {\n    // the exclude isn't working, nor is there a subPackages options as docs suggest there should be\n    // we do not want the com.netflix.hystrix.util package include\n    exclude '**/util/**'\n\n    options {\n        doclet = \"org.benjchristensen.doclet.DocletExclude\"\n        docletpath = [rootProject.file('./gradle/doclet-exclude.jar')]\n        stylesheetFile = rootProject.file('./gradle/javadocStyleSheet.css')\n        windowTitle = \"Hystrix Javadoc ${project.version}\"\n    }\n    options.addStringOption('top').value = '<a href=\"https://github.com/Netflix/Hystrix\"><img width=\"92\" height=\"79\" border=\"0\" align=\"left\" src=\"http://netflix.github.com/Hystrix/images/hystrix-logo-small.png\"></a><h2 class=\"title\" style=\"padding-top:40px\">Hystrix: Latency and Fault Tolerance for Distributed Systems</h2>'\n}\n\njmh {\n    fork = 10\n    iterations = 3\n    jmhVersion = '1.15'\n    profilers = ['gc']\n    threads = 8\n    warmup = '1s'\n    warmupBatchSize = 1\n    warmupIterations = 5\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/CollapserPerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.infra.Blackhole;\nimport rx.Observable;\nimport rx.Subscription;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\npublic class CollapserPerfTest {\n    @State(Scope.Benchmark)\n    public static class ThreadPoolState {\n        HystrixThreadPool hystrixThreadPool;\n\n        @Setup\n        public void setUp() {\n            hystrixThreadPool = new HystrixThreadPool.HystrixThreadPoolDefault(\n                    HystrixThreadPoolKey.Factory.asKey(\"PERF\")\n                    , HystrixThreadPoolProperties.Setter().withCoreSize(100));\n        }\n\n        @TearDown\n        public void tearDown() {\n            hystrixThreadPool.getExecutor().shutdownNow();\n        }\n    }\n\n    @State(Scope.Thread)\n    public static class CollapserState {\n        @Param({\"1\", \"10\", \"100\", \"1000\"})\n        int numToCollapse;\n\n        @Param({\"1\", \"1000\", \"1000000\"})\n        int blackholeConsumption;\n\n        HystrixRequestContext reqContext;\n        Observable<String> executionHandle;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            reqContext = HystrixRequestContext.initializeContext();\n\n            List<Observable<String>> os = new ArrayList<Observable<String>>();\n\n            for (int i = 0; i < numToCollapse; i++) {\n                IdentityCollapser collapser = new IdentityCollapser(i, blackholeConsumption);\n                os.add(collapser.observe());\n            }\n\n            executionHandle = Observable.merge(os);\n        }\n\n        @TearDown(Level.Invocation)\n        public void tearDown() {\n            reqContext.shutdown();\n        }\n\n    }\n\n    private static class IdentityCollapser extends HystrixCollapser<List<String>, String, String> {\n\n        private final int arg;\n        private final int blackholeConsumption;\n\n        IdentityCollapser(int arg, int blackholeConsumption) {\n            super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey(\"COLLAPSER\")).andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withMaxRequestsInBatch(1000).withTimerDelayInMilliseconds(1)));\n            this.arg = arg;\n            this.blackholeConsumption = blackholeConsumption;\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return arg + \"\";\n        }\n\n        @Override\n        protected HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> collapsedRequests) {\n            List<String> args = new ArrayList<String>();\n            for (CollapsedRequest<String, String> collapsedReq: collapsedRequests) {\n                args.add(collapsedReq.getArgument());\n            }\n            return new BatchCommand(args, blackholeConsumption);\n        }\n\n        @Override\n        protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, String>> collapsedRequests) {\n            for (CollapsedRequest<String, String> collapsedReq: collapsedRequests) {\n                String requestArg = collapsedReq.getArgument();\n                String response = \"<not found>\";\n                for (String responsePiece: batchResponse) {\n                    if (responsePiece.startsWith(requestArg + \":\")) {\n                        response = responsePiece;\n                        break;\n                    }\n                }\n                collapsedReq.setResponse(response);\n            }\n        }\n    }\n\n    private static class BatchCommand extends HystrixCommand<List<String>> {\n        private final List<String> inputArgs;\n        private final int blackholeConsumption;\n\n        BatchCommand(List<String> inputArgs, int blackholeConsumption) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"PERF\")).andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(\"PERF\")));\n            this.inputArgs = inputArgs;\n            this.blackholeConsumption = blackholeConsumption;\n        }\n\n        @Override\n        protected List<String> run() throws Exception {\n            Blackhole.consumeCPU(blackholeConsumption);\n            List<String> toReturn = new ArrayList<String>();\n            for (String inputArg: inputArgs) {\n                toReturn.add(inputArg + \":1\");\n            }\n            return toReturn;\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.SECONDS)\n    public List<String> observeCollapsedAndWait(CollapserState collapserState, ThreadPoolState threadPoolState) {\n        return collapserState.executionHandle.toList().toBlocking().single();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/CommandConstructionPerfTest.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class CommandConstructionPerfTest {\n\n    static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Group\");\n\n    @Benchmark\n    @BenchmarkMode({Mode.SingleShotTime})\n    @OutputTimeUnit(TimeUnit.MICROSECONDS)\n    public HystrixCommand constructHystrixCommandByGroupKeyOnly() {\n        return new HystrixCommand<Integer>(groupKey) {\n            @Override\n            protected Integer run() throws Exception {\n                return 1;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/CommandExecutionAndConcurrentMetricsReadPerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.GroupThreads;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class CommandExecutionAndConcurrentMetricsReadPerfTest {\n    @State(Scope.Thread)\n    public static class CommandState {\n        HystrixCommand<Integer> command;\n\n        @Param({\"THREAD\", \"SEMAPHORE\"})\n        public HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy;\n\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            command = new HystrixCommand<Integer>(\n                    HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"PERF\"))\n                            .andCommandPropertiesDefaults(\n                                    HystrixCommandProperties.Setter()\n                                            .withExecutionIsolationStrategy(isolationStrategy)\n                                            .withRequestCacheEnabled(true)\n                                            .withRequestLogEnabled(true)\n                                            .withCircuitBreakerEnabled(true)\n                                            .withCircuitBreakerForceOpen(false)\n                            )\n                            .andThreadPoolPropertiesDefaults(\n                                    HystrixThreadPoolProperties.Setter()\n                                            .withCoreSize(100)\n                            )\n            ) {\n                @Override\n                protected Integer run() throws Exception {\n                    return 1;\n                }\n\n                @Override\n                protected Integer getFallback() {\n                    return 2;\n                }\n            };\n        }\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer writeHeavyCommandExecution(CommandState state) {\n        return state.command.observe().toBlocking().first();\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long writeHeavyReadMetrics(CommandState state) {\n        HystrixCommandMetrics metrics = state.command.getMetrics();\n        return metrics.getExecutionTimeMean()\n                + metrics.getExecutionTimePercentile(50)\n                + metrics.getExecutionTimePercentile(75)\n                + metrics.getExecutionTimePercentile(99)\n                + metrics.getCumulativeCount(HystrixEventType.SUCCESS)\n                + metrics.getRollingCount(HystrixEventType.FAILURE)\n                + metrics.getRollingMaxConcurrentExecutions();\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer evenSplitOfWritesAndReadsCommandExecution(CommandState state) {\n        return state.command.observe().toBlocking().first();\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long evenSplitOfWritesAndReadsReadMetrics(CommandState state) {\n        HystrixCommandMetrics metrics = state.command.getMetrics();\n        return metrics.getExecutionTimeMean()\n                + metrics.getExecutionTimePercentile(50)\n                + metrics.getExecutionTimePercentile(75)\n                + metrics.getExecutionTimePercentile(99)\n                + metrics.getCumulativeCount(HystrixEventType.SUCCESS)\n                + metrics.getRollingCount(HystrixEventType.FAILURE)\n                + metrics.getRollingMaxConcurrentExecutions();\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer readHeavyCommandExecution(CommandState state) {\n        return state.command.observe().toBlocking().first();\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Long readHeavyReadMetrics(CommandState state) {\n        HystrixCommandMetrics metrics = state.command.getMetrics();\n        return metrics.getExecutionTimeMean()\n                + metrics.getExecutionTimePercentile(50)\n                + metrics.getExecutionTimePercentile(75)\n                + metrics.getExecutionTimePercentile(99)\n                + metrics.getCumulativeCount(HystrixEventType.SUCCESS)\n                + metrics.getRollingCount(HystrixEventType.FAILURE)\n                + metrics.getRollingMaxConcurrentExecutions();\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/CommandExecutionPerfTest.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.infra.Blackhole;\nimport rx.Observable;\nimport rx.functions.Func0;\nimport rx.schedulers.Schedulers;\n\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\n/**\n  * Note that the hystrixExecute test must be run on a forked JVM.  Otherwise, the initial properties that get\n  * set for the command apply to all runs.  This would leave the command as THREAD-isolated in all test, for example.\n  */\npublic class CommandExecutionPerfTest {\n\n    private static HystrixCommandProperties.Setter threadIsolatedCommandDefaults = HystrixCommandProperties.Setter()\n            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)\n            .withRequestCacheEnabled(true)\n            .withRequestLogEnabled(true)\n            .withCircuitBreakerEnabled(true)\n            .withCircuitBreakerForceOpen(false);\n\n    private static HystrixCommandProperties.Setter threadIsolatedFailFastCommandDefaults = HystrixCommandProperties.Setter()\n            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)\n            .withRequestCacheEnabled(true)\n            .withRequestLogEnabled(true)\n            .withCircuitBreakerEnabled(true)\n            .withCircuitBreakerForceOpen(true);\n\n    private static HystrixCommandProperties.Setter semaphoreIsolatedCommandDefaults = HystrixCommandProperties.Setter()\n            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)\n            .withRequestCacheEnabled(true)\n            .withRequestLogEnabled(true)\n            .withCircuitBreakerEnabled(true)\n            .withCircuitBreakerForceOpen(false);\n\n    private static HystrixCommandProperties.Setter semaphoreIsolatedFailFastCommandDefaults = HystrixCommandProperties.Setter()\n            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)\n            .withRequestCacheEnabled(true)\n            .withRequestLogEnabled(true)\n            .withCircuitBreakerEnabled(true)\n            .withCircuitBreakerForceOpen(true);\n\n    private static HystrixThreadPoolProperties.Setter threadPoolDefaults = HystrixThreadPoolProperties.Setter()\n            .withCoreSize(100);\n\n    private static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"PERF\");\n\n    private static HystrixCommandProperties.Setter getCommandSetter(HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy, boolean forceOpen) {\n        switch (isolationStrategy) {\n            case THREAD:\n                if (forceOpen) {\n                    return threadIsolatedFailFastCommandDefaults;\n                } else {\n                    return threadIsolatedCommandDefaults;\n                }\n            default:\n                if (forceOpen) {\n                    return semaphoreIsolatedFailFastCommandDefaults;\n                } else {\n                    return semaphoreIsolatedCommandDefaults;\n                }\n        }\n    }\n\n    @State(Scope.Thread)\n    public static class BlackholeState {\n        //amount of \"work\" to give to CPU\n        @Param({\"1\", \"100\", \"10000\"})\n        public int blackholeConsumption;\n    }\n\n    @State(Scope.Thread)\n    public static class CommandState {\n        HystrixCommand<Integer> command;\n        HystrixRequestContext requestContext;\n\n        @Param({\"true\", \"false\"})\n        public boolean forceOpen;\n\n        @Param({\"true\", \"false\"})\n        public boolean setUpRequestContext;\n\n        @Param({\"THREAD\", \"SEMAPHORE\"})\n        public HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy;\n\n        //amount of \"work\" to give to CPU\n        @Param({\"1\", \"100\", \"10000\"})\n        public int blackholeConsumption;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            if (setUpRequestContext) {\n                requestContext = HystrixRequestContext.initializeContext();\n            }\n\n            command = new HystrixCommand<Integer>(\n                    HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"PERF\"))\n                            .andCommandPropertiesDefaults(getCommandSetter(isolationStrategy, forceOpen))\n                            .andThreadPoolPropertiesDefaults(threadPoolDefaults)\n            ) {\n                @Override\n                protected Integer run() throws Exception {\n                    Blackhole.consumeCPU(blackholeConsumption);\n                    return 1;\n                }\n\n                @Override\n                protected Integer getFallback() {\n                    return 2;\n                }\n            };\n        }\n\n        @TearDown(Level.Invocation)\n        public void tearDown() {\n            if (setUpRequestContext) {\n                requestContext.shutdown();\n            }\n        }\n    }\n\n    @State(Scope.Thread)\n    public static class ObservableCommandState {\n        HystrixObservableCommand<Integer> command;\n        HystrixRequestContext requestContext;\n\n        @Param({\"true\", \"false\"})\n        public boolean forceOpen;\n\n        @Param({\"true\", \"false\"})\n        public boolean setUpRequestContext;\n\n        //amount of \"work\" to give to CPU\n        @Param({\"1\", \"100\", \"10000\"})\n        public int blackholeConsumption;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            if (setUpRequestContext) {\n                requestContext = HystrixRequestContext.initializeContext();\n            }\n\n            command = new HystrixObservableCommand<Integer>(\n                    HystrixObservableCommand.Setter.withGroupKey(groupKey)\n                    .andCommandPropertiesDefaults(getCommandSetter(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE, forceOpen))\n            ) {\n                @Override\n                protected Observable<Integer> construct() {\n                    return Observable.defer(new Func0<Observable<Integer>>() {\n                        @Override\n                        public Observable<Integer> call() {\n                            Blackhole.consumeCPU(blackholeConsumption);\n                            return Observable.just(1);\n                        }\n                    }).subscribeOn(Schedulers.computation());\n                }\n            };\n        }\n\n        @TearDown(Level.Invocation)\n        public void tearDown() {\n            if (setUpRequestContext) {\n                requestContext.shutdown();\n            }\n        }\n    }\n\n    @State(Scope.Benchmark)\n    public static class ExecutorState {\n        ExecutorService executorService;\n\n        @Setup\n        public void setUp() {\n            executorService = Executors.newFixedThreadPool(100);\n        }\n\n        @TearDown\n        public void tearDown() {\n            List<Runnable> runnables = executorService.shutdownNow();\n        }\n    }\n\n    @State(Scope.Benchmark)\n    public static class ThreadPoolState {\n        HystrixThreadPool hystrixThreadPool;\n\n        @Setup\n        public void setUp() {\n            hystrixThreadPool = new HystrixThreadPool.HystrixThreadPoolDefault(\n                    HystrixThreadPoolKey.Factory.asKey(\"PERF\")\n                    , HystrixThreadPoolProperties.Setter().withCoreSize(100));\n        }\n\n        @TearDown\n        public void tearDown() {\n            hystrixThreadPool.getExecutor().shutdownNow();\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer baselineExecute(BlackholeState bhState) {\n        Blackhole.consumeCPU(bhState.blackholeConsumption);\n        return 1;\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer baselineQueue(ExecutorState state, final BlackholeState bhState) throws InterruptedException, ExecutionException {\n        try {\n            return state.executorService.submit(new Callable<Integer>() {\n                @Override\n                public Integer call() throws Exception {\n                    Blackhole.consumeCPU(bhState.blackholeConsumption);\n                    return 1;\n                }\n            }).get();\n        } catch (Throwable t) {\n            return 2;\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer baselineSyncObserve(final BlackholeState bhState) throws InterruptedException {\n        Observable<Integer> syncObservable = Observable.defer(new Func0<Observable<Integer>>() {\n            @Override\n            public Observable<Integer> call() {\n                Blackhole.consumeCPU(bhState.blackholeConsumption);\n                return Observable.just(1);\n            }\n        });\n\n        try {\n            return syncObservable.toBlocking().first();\n        } catch (Throwable t) {\n            return 2;\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer baselineAsyncComputationObserve(final BlackholeState bhState) throws InterruptedException {\n        Observable<Integer> asyncObservable = Observable.defer(new Func0<Observable<Integer>>() {\n            @Override\n            public Observable<Integer> call() {\n                Blackhole.consumeCPU(bhState.blackholeConsumption);\n                return Observable.just(1);\n            }\n        }).subscribeOn(Schedulers.computation());\n\n        try {\n            return asyncObservable.toBlocking().first();\n        } catch (Throwable t) {\n            return 2;\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer baselineAsyncCustomThreadPoolObserve(ThreadPoolState state, final BlackholeState bhState) {\n        Observable<Integer> asyncObservable = Observable.defer(new Func0<Observable<Integer>>() {\n            @Override\n            public Observable<Integer> call() {\n                Blackhole.consumeCPU(bhState.blackholeConsumption);\n                return Observable.just(1);\n            }\n        }).subscribeOn(state.hystrixThreadPool.getScheduler());\n        try {\n            return asyncObservable.toBlocking().first();\n        } catch (Throwable t) {\n            return 2;\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer hystrixExecute(CommandState state) {\n        return state.command.execute();\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public Integer hystrixObserve(ObservableCommandState state) {\n        return state.command.observe().toBlocking().first();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/ObservableCollapserPerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixObservableCollapser;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesCollapserDefault;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.infra.Blackhole;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\nimport rx.schedulers.Schedulers;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\npublic class ObservableCollapserPerfTest {\n\n    @State(Scope.Thread)\n    public static class CollapserState {\n        @Param({\"1\", \"10\", \"100\", \"1000\"})\n        int numToCollapse;\n\n        @Param({\"1\", \"10\", \"100\"})\n        int numResponsesPerArg;\n\n        @Param({\"1\", \"1000\", \"1000000\"})\n        int blackholeConsumption;\n\n        HystrixRequestContext reqContext;\n        Observable<String> executionHandle;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            reqContext = HystrixRequestContext.initializeContext();\n\n            List<Observable<String>> os = new ArrayList<Observable<String>>();\n\n            for (int i = 0; i < numToCollapse; i++) {\n                TestCollapserWithMultipleResponses collapser = new TestCollapserWithMultipleResponses(i, numResponsesPerArg, blackholeConsumption);\n                os.add(collapser.observe());\n            }\n\n            executionHandle = Observable.merge(os);\n        }\n\n        @TearDown(Level.Invocation)\n        public void tearDown() {\n            reqContext.shutdown();\n        }\n\n    }\n\n    //TODO wire in synthetic timer\n    private static class TestCollapserWithMultipleResponses extends HystrixObservableCollapser<String, String, String, String> {\n\n        private final String arg;\n        private final static Map<String, Integer> emitsPerArg;\n        private final int blackholeConsumption;\n        private final boolean commandConstructionFails;\n        private final Func1<String, String> keyMapper;\n        private final Action1<HystrixCollapser.CollapsedRequest<String, String>> onMissingResponseHandler;\n\n        static {\n            emitsPerArg = new HashMap<String, Integer>();\n        }\n\n        public TestCollapserWithMultipleResponses(int arg, int numResponsePerArg, int blackholeConsumption) {\n            super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey(\"COLLAPSER\")).andScope(Scope.REQUEST).andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withMaxRequestsInBatch(1000).withTimerDelayInMilliseconds(1)));\n            this.arg = arg + \"\";\n            emitsPerArg.put(this.arg, numResponsePerArg);\n            this.blackholeConsumption = blackholeConsumption;\n            commandConstructionFails = false;\n            keyMapper = new Func1<String, String>() {\n                @Override\n                public String call(String s) {\n                    return s.substring(0, s.indexOf(\":\"));\n                }\n            };\n            onMissingResponseHandler = new Action1<HystrixCollapser.CollapsedRequest<String, String>>() {\n                @Override\n                public void call(HystrixCollapser.CollapsedRequest<String, String> collapsedReq) {\n                    collapsedReq.setResponse(\"missing:missing\");\n                }\n            };\n\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return arg;\n        }\n\n        @Override\n        protected HystrixObservableCommand<String> createCommand(Collection<HystrixCollapser.CollapsedRequest<String, String>> collapsedRequests) {\n            if (commandConstructionFails) {\n                throw new RuntimeException(\"Exception thrown in command construction\");\n            } else {\n                List<Integer> args = new ArrayList<Integer>();\n\n                for (HystrixCollapser.CollapsedRequest<String, String> collapsedRequest : collapsedRequests) {\n                    String stringArg = collapsedRequest.getArgument();\n                    int intArg = Integer.parseInt(stringArg);\n                    args.add(intArg);\n                }\n\n                return new TestCollapserCommandWithMultipleResponsePerArgument(args, emitsPerArg, blackholeConsumption);\n            }\n        }\n\n        //Data comes back in the form: 1:1, 1:2, 1:3, 2:2, 2:4, 2:6.\n        //This method should use the first half of that string as the request arg\n        @Override\n        protected Func1<String, String> getBatchReturnTypeKeySelector() {\n            return keyMapper;\n\n        }\n\n        @Override\n        protected Func1<String, String> getRequestArgumentKeySelector() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n\n        @Override\n        protected void onMissingResponse(HystrixCollapser.CollapsedRequest<String, String> r) {\n            onMissingResponseHandler.call(r);\n\n        }\n\n        @Override\n        protected Func1<String, String> getBatchReturnTypeToResponseTypeMapper() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n    }\n\n    private static class TestCollapserCommandWithMultipleResponsePerArgument extends HystrixObservableCommand<String> {\n\n        private final List<Integer> args;\n        private final Map<String, Integer> emitsPerArg;\n        private final int blackholeConsumption;\n\n        TestCollapserCommandWithMultipleResponsePerArgument(List<Integer> args, Map<String, Integer> emitsPerArg, int blackholeConsumption) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"COLLAPSER_MULTI\")).andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));\n            this.args = args;\n            this.emitsPerArg = emitsPerArg;\n            this.blackholeConsumption = blackholeConsumption;\n        }\n\n        @Override\n        protected Observable<String> construct() {\n            return Observable.create(new Observable.OnSubscribe<String>() {\n                @Override\n                public void call(Subscriber<? super String> subscriber) {\n                    try {\n                        Blackhole.consumeCPU(blackholeConsumption);\n                        for (Integer arg: args) {\n                            int numEmits = emitsPerArg.get(arg.toString());\n                            for (int j = 1; j < numEmits + 1; j++) {\n                                subscriber.onNext(arg + \":\" + (arg * j));\n                            }\n                        }\n                    } catch (Throwable ex) {\n                        subscriber.onError(ex);\n                    }\n                    subscriber.onCompleted();\n                }\n            }).subscribeOn(Schedulers.computation());\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.SECONDS)\n    public List<String> observeCollapsedAndWait(CollapserState collapserState) {\n        return collapserState.executionHandle.toList().toBlocking().single();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/RollingMaxPerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.util.HystrixRollingNumber;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.GroupThreads;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\n\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\npublic class RollingMaxPerfTest {\n    @State(Scope.Thread)\n    public static class CounterState {\n        HystrixRollingNumber counter;\n\n        @Setup(Level.Iteration)\n        public void setUp() {\n            counter = new HystrixRollingNumber(100, 10);\n        }\n    }\n\n    @State(Scope.Thread)\n    public static class ValueState {\n        final Random r = new Random();\n\n        int value;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            value = r.nextInt(100);\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber writeOnly(CounterState counterState, ValueState valueState) {\n        counterState.counter.updateRollingMax(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long readOnly(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getRollingMaxValue(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE);\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber writeHeavyUpdateMax(CounterState counterState, ValueState valueState) {\n        counterState.counter.updateRollingMax(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long writeHeavyReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getRollingMaxValue(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE);\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber evenSplitUpdateMax(CounterState counterState, ValueState valueState) {\n        counterState.counter.updateRollingMax(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long evenSplitReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getRollingMaxValue(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE);\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber readHeavyUpdateMax(CounterState counterState, ValueState valueState) {\n        counterState.counter.updateRollingMax(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long readHeavyReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getRollingMaxValue(HystrixRollingNumberEvent.COMMAND_MAX_ACTIVE);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/RollingNumberPerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.util.HystrixRollingNumber;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.GroupThreads;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\n\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\npublic class RollingNumberPerfTest {\n    @State(Scope.Thread)\n    public static class CounterState {\n        HystrixRollingNumber counter;\n\n        @Setup(Level.Iteration)\n        public void setUp() {\n            counter = new HystrixRollingNumber(100, 10);\n        }\n    }\n\n    @State(Scope.Thread)\n    public static class ValueState {\n        final Random r = new Random();\n\n        int value;\n        HystrixRollingNumberEvent type;\n\n        @Setup(Level.Invocation)\n        public void setUp() {\n            value = r.nextInt(100);\n            int typeInt = r.nextInt(3);\n            switch(typeInt) {\n                case 0:\n                    type = HystrixRollingNumberEvent.SUCCESS;\n                    break;\n                case 1:\n                    type = HystrixRollingNumberEvent.FAILURE;\n                    break;\n                case 2:\n                    type = HystrixRollingNumberEvent.TIMEOUT;\n                    break;\n                default: throw new RuntimeException(\"Unexpected : \" + typeInt);\n            }\n        }\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber writeOnly(CounterState counterState, ValueState valueState) {\n        counterState.counter.add(valueState.type, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long readOnly(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getCumulativeSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.TIMEOUT) +\n                counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getRollingSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT);\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber writeHeavyCounterAdd(CounterState counterState, ValueState valueState) {\n        counterState.counter.add(valueState.type, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"writeHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long writeHeavyReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getCumulativeSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.TIMEOUT) +\n                counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getRollingSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT);\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber evenSplitCounterAdd(CounterState counterState, ValueState valueState) {\n        counterState.counter.add(valueState.type, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"evenSplit\")\n    @GroupThreads(4)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long evenSplitReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getCumulativeSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.TIMEOUT) +\n                counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getRollingSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT);\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(1)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public HystrixRollingNumber readHeavyCounterAdd(CounterState counterState, ValueState valueState) {\n        counterState.counter.add(valueState.type, valueState.value);\n        return counterState.counter;\n    }\n\n    @Benchmark\n    @Group(\"readHeavy\")\n    @GroupThreads(7)\n    @BenchmarkMode({Mode.Throughput})\n    @OutputTimeUnit(TimeUnit.MILLISECONDS)\n    public long readHeavyReadMetrics(CounterState counterState) {\n        HystrixRollingNumber counter = counterState.counter;\n        return counter.getCumulativeSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getCumulativeSum(HystrixRollingNumberEvent.TIMEOUT) +\n                counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS) +\n                counter.getRollingSum(HystrixRollingNumberEvent.FAILURE) +\n                counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/jmh/java/com/netflix/hystrix/perf/RollingPercentilePerfTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.perf;\n\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixRollingPercentile;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.GroupThreads;\nimport org.openjdk.jmh.annotations.Level;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Param;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\n\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\npublic class RollingPercentilePerfTest {\n\t@State(Scope.Thread)\n\tpublic static class PercentileState {\n\t\tHystrixRollingPercentile percentile;\n\n\t\t@Param({\"true\", \"false\"})\n\t\tpublic boolean percentileEnabled;\n\n\t\t@Setup(Level.Iteration)\n\t\tpublic void setUp() {\n\t\t\tpercentile = new HystrixRollingPercentile(100, 10, 1000, HystrixProperty.Factory.asProperty(percentileEnabled));\n\t\t}\n\t}\n\n\t@State(Scope.Thread)\n\tpublic static class LatencyState {\n\t\tfinal Random r = new Random();\n\n\t\tint latency;\n\n\t\t@Setup(Level.Invocation)\n\t\tpublic void setUp() {\n\t\t\tlatency = r.nextInt(100);\n\t\t}\n\t}\n\n\t@Benchmark\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic HystrixRollingPercentile writeOnly(PercentileState percentileState, LatencyState latencyState) {\n\t\tpercentileState.percentile.addValue(latencyState.latency);\n\t\treturn percentileState.percentile;\n\t}\n\n\t@Benchmark\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic int readOnly(PercentileState percentileState) {\n\t\tHystrixRollingPercentile percentile = percentileState.percentile;\n\t\treturn percentile.getMean() +\n\t\t\t\tpercentile.getPercentile(10) +\n\t\t\t\tpercentile.getPercentile(25) +\n\t\t\t\tpercentile.getPercentile(50) +\n\t\t\t\tpercentile.getPercentile(75) +\n\t\t\t\tpercentile.getPercentile(90) +\n\t\t\t\tpercentile.getPercentile(95) +\n\t\t\t\tpercentile.getPercentile(99) +\n\t\t\t\tpercentile.getPercentile(99.5);\n\t}\n\n\t@Benchmark\n\t@Group(\"writeHeavy\")\n\t@GroupThreads(7)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic HystrixRollingPercentile writeHeavyLatencyAdd(PercentileState percentileState, LatencyState latencyState) {\n\t\tpercentileState.percentile.addValue(latencyState.latency);\n\t\treturn percentileState.percentile;\n\t}\n\n\t@Benchmark\n\t@Group(\"writeHeavy\")\n\t@GroupThreads(1)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic int writeHeavyReadMetrics(PercentileState percentileState) {\n\t\tHystrixRollingPercentile percentile = percentileState.percentile;\n\t\treturn percentile.getMean() +\n\t\t\t\tpercentile.getPercentile(10) +\n\t\t\t\tpercentile.getPercentile(25) +\n\t\t\t\tpercentile.getPercentile(50) +\n\t\t\t\tpercentile.getPercentile(75) +\n\t\t\t\tpercentile.getPercentile(90) +\n\t\t\t\tpercentile.getPercentile(95) +\n\t\t\t\tpercentile.getPercentile(99) +\n\t\t\t\tpercentile.getPercentile(99.5);\n\t}\n\n\t@Benchmark\n\t@Group(\"evenSplit\")\n\t@GroupThreads(4)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic HystrixRollingPercentile evenSplitLatencyAdd(PercentileState percentileState, LatencyState latencyState) {\n\t\tpercentileState.percentile.addValue(latencyState.latency);\n\t\treturn percentileState.percentile;\n\t}\n\n\t@Benchmark\n\t@Group(\"evenSplit\")\n\t@GroupThreads(4)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic int evenSplitReadMetrics(PercentileState percentileState) {\n\t\tHystrixRollingPercentile percentile = percentileState.percentile;\n\t\treturn percentile.getMean() +\n\t\t\t\tpercentile.getPercentile(10) +\n\t\t\t\tpercentile.getPercentile(25) +\n\t\t\t\tpercentile.getPercentile(50) +\n\t\t\t\tpercentile.getPercentile(75) +\n\t\t\t\tpercentile.getPercentile(90) +\n\t\t\t\tpercentile.getPercentile(95) +\n\t\t\t\tpercentile.getPercentile(99) +\n\t\t\t\tpercentile.getPercentile(99.5);\n\t}\n\n\t@Benchmark\n\t@Group(\"readHeavy\")\n\t@GroupThreads(1)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic HystrixRollingPercentile readHeavyLatencyAdd(PercentileState percentileState, LatencyState latencyState) {\n\t\tpercentileState.percentile.addValue(latencyState.latency);\n\t\treturn percentileState.percentile;\n\t}\n\n\t@Benchmark\n\t@Group(\"readHeavy\")\n\t@GroupThreads(7)\n\t@BenchmarkMode({Mode.Throughput})\n\t@OutputTimeUnit(TimeUnit.MILLISECONDS)\n\tpublic int readHeavyReadMetrics(PercentileState percentileState) {\n\t\tHystrixRollingPercentile percentile = percentileState.percentile;\n\t\treturn percentile.getMean() +\n\t\t\t\tpercentile.getPercentile(10) +\n\t\t\t\tpercentile.getPercentile(25) +\n\t\t\t\tpercentile.getPercentile(50) +\n\t\t\t\tpercentile.getPercentile(75) +\n\t\t\t\tpercentile.getPercentile(90) +\n\t\t\t\tpercentile.getPercentile(95) +\n\t\t\t\tpercentile.getPercentile(99) +\n\t\t\t\tpercentile.getPercentile(99.5);\n\t}\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker.NoOpCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.exception.ExceptionNotWrappedByHystrix;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException.FailureType;\nimport com.netflix.hystrix.exception.HystrixTimeoutException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixTimer;\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Notification;\nimport rx.Observable;\nimport rx.Observable.Operator;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.subjects.ReplaySubject;\nimport rx.subscriptions.CompositeSubscription;\n\nimport java.lang.ref.Reference;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/* package */abstract class AbstractCommand<R> implements HystrixInvokableInfo<R>, HystrixObservable<R> {\n    private static final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);\n    protected final HystrixCircuitBreaker circuitBreaker;\n    protected final HystrixThreadPool threadPool;\n    protected final HystrixThreadPoolKey threadPoolKey;\n    protected final HystrixCommandProperties properties;\n\n    protected enum TimedOutStatus {\n        NOT_EXECUTED, COMPLETED, TIMED_OUT\n    }\n\n    protected enum CommandState {\n        NOT_STARTED, OBSERVABLE_CHAIN_CREATED, USER_CODE_EXECUTED, UNSUBSCRIBED, TERMINAL\n    }\n\n    protected enum ThreadState {\n        NOT_USING_THREAD, STARTED, UNSUBSCRIBED, TERMINAL\n    }\n\n    protected final HystrixCommandMetrics metrics;\n\n    protected final HystrixCommandKey commandKey;\n    protected final HystrixCommandGroupKey commandGroup;\n\n    /**\n     * Plugin implementations\n     */\n    protected final HystrixEventNotifier eventNotifier;\n    protected final HystrixConcurrencyStrategy concurrencyStrategy;\n    protected final HystrixCommandExecutionHook executionHook;\n\n    /* FALLBACK Semaphore */\n    protected final TryableSemaphore fallbackSemaphoreOverride;\n    /* each circuit has a semaphore to restrict concurrent fallback execution */\n    protected static final ConcurrentHashMap<String, TryableSemaphore> fallbackSemaphorePerCircuit = new ConcurrentHashMap<String, TryableSemaphore>();\n    /* END FALLBACK Semaphore */\n\n    /* EXECUTION Semaphore */\n    protected final TryableSemaphore executionSemaphoreOverride;\n    /* each circuit has a semaphore to restrict concurrent fallback execution */\n    protected static final ConcurrentHashMap<String, TryableSemaphore> executionSemaphorePerCircuit = new ConcurrentHashMap<String, TryableSemaphore>();\n    /* END EXECUTION Semaphore */\n\n    protected final AtomicReference<Reference<TimerListener>> timeoutTimer = new AtomicReference<Reference<TimerListener>>();\n\n    protected AtomicReference<CommandState> commandState = new AtomicReference<CommandState>(CommandState.NOT_STARTED);\n    protected AtomicReference<ThreadState> threadState = new AtomicReference<ThreadState>(ThreadState.NOT_USING_THREAD);\n\n    /*\n     * {@link ExecutionResult} refers to what happened as the user-provided code ran.  If request-caching is used,\n     * then multiple command instances will have a reference to the same {@link ExecutionResult}.  So all values there\n     * should be the same, even in the presence of request-caching.\n     *\n     * If some values are not properly shareable, then they belong on the command instance, so they are not visible to\n     * other commands.\n     *\n     * Examples: RESPONSE_FROM_CACHE, CANCELLED HystrixEventTypes\n     */\n    protected volatile ExecutionResult executionResult = ExecutionResult.EMPTY; //state on shared execution\n\n    protected volatile boolean isResponseFromCache = false;\n    protected volatile ExecutionResult executionResultAtTimeOfCancellation;\n    protected volatile long commandStartTimestamp = -1L;\n\n    /* If this command executed and timed-out */\n    protected final AtomicReference<TimedOutStatus> isCommandTimedOut = new AtomicReference<TimedOutStatus>(TimedOutStatus.NOT_EXECUTED);\n    protected volatile Action0 endCurrentThreadExecutingCommand;\n\n    /**\n     * Instance of RequestCache logic\n     */\n    protected final HystrixRequestCache requestCache;\n    protected final HystrixRequestLog currentRequestLog;\n\n    // this is a micro-optimization but saves about 1-2microseconds (on 2011 MacBook Pro) \n    // on the repetitive string processing that will occur on the same classes over and over again\n    private static ConcurrentHashMap<Class<?>, String> defaultNameCache = new ConcurrentHashMap<Class<?>, String>();\n\n    protected static ConcurrentHashMap<HystrixCommandKey, Boolean> commandContainsFallback = new ConcurrentHashMap<HystrixCommandKey, Boolean>();\n\n    /* package */static String getDefaultNameFromClass(Class<?> cls) {\n        String fromCache = defaultNameCache.get(cls);\n        if (fromCache != null) {\n            return fromCache;\n        }\n        // generate the default\n        // default HystrixCommandKey to use if the method is not overridden\n        String name = cls.getSimpleName();\n        if (name.equals(\"\")) {\n            // we don't have a SimpleName (anonymous inner class) so use the full class name\n            name = cls.getName();\n            name = name.substring(name.lastIndexOf('.') + 1, name.length());\n        }\n        defaultNameCache.put(cls, name);\n        return name;\n    }\n\n    protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,\n            HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,\n            HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,\n            HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {\n\n        this.commandGroup = initGroupKey(group);\n        this.commandKey = initCommandKey(key, getClass());\n        this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults);\n        this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get());\n        this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties);\n        this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics);\n        this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults);\n\n        //Strategies from plugins\n        this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();\n        this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();\n        HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(this.commandKey, this.commandGroup, this.metrics, this.circuitBreaker, this.properties);\n        this.executionHook = initExecutionHook(executionHook);\n\n        this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);\n        this.currentRequestLog = initRequestLog(this.properties.requestLogEnabled().get(), this.concurrencyStrategy);\n\n        /* fallback semaphore override if applicable */\n        this.fallbackSemaphoreOverride = fallbackSemaphore;\n\n        /* execution semaphore override if applicable */\n        this.executionSemaphoreOverride = executionSemaphore;\n    }\n\n    private static HystrixCommandGroupKey initGroupKey(final HystrixCommandGroupKey fromConstructor) {\n        if (fromConstructor == null) {\n            throw new IllegalStateException(\"HystrixCommandGroup can not be NULL\");\n        } else {\n            return fromConstructor;\n        }\n    }\n\n    private static HystrixCommandKey initCommandKey(final HystrixCommandKey fromConstructor, Class<?> clazz) {\n        if (fromConstructor == null || fromConstructor.name().trim().equals(\"\")) {\n            final String keyName = getDefaultNameFromClass(clazz);\n            return HystrixCommandKey.Factory.asKey(keyName);\n        } else {\n            return fromConstructor;\n        }\n    }\n\n    private static HystrixCommandProperties initCommandProperties(HystrixCommandKey commandKey, HystrixPropertiesStrategy propertiesStrategy, HystrixCommandProperties.Setter commandPropertiesDefaults) {\n        if (propertiesStrategy == null) {\n            return HystrixPropertiesFactory.getCommandProperties(commandKey, commandPropertiesDefaults);\n        } else {\n            // used for unit testing\n            return propertiesStrategy.getCommandProperties(commandKey, commandPropertiesDefaults);\n        }\n    }\n\n    /*\n     * ThreadPoolKey\n     *\n     * This defines which thread-pool this command should run on.\n     *\n     * It uses the HystrixThreadPoolKey if provided, then defaults to use HystrixCommandGroup.\n     *\n     * It can then be overridden by a property if defined so it can be changed at runtime.\n     */\n    private static HystrixThreadPoolKey initThreadPoolKey(HystrixThreadPoolKey threadPoolKey, HystrixCommandGroupKey groupKey, String threadPoolKeyOverride) {\n        if (threadPoolKeyOverride == null) {\n            // we don't have a property overriding the value so use either HystrixThreadPoolKey or HystrixCommandGroup\n            if (threadPoolKey == null) {\n                /* use HystrixCommandGroup if HystrixThreadPoolKey is null */\n                return HystrixThreadPoolKey.Factory.asKey(groupKey.name());\n            } else {\n                return threadPoolKey;\n            }\n        } else {\n            // we have a property defining the thread-pool so use it instead\n            return HystrixThreadPoolKey.Factory.asKey(threadPoolKeyOverride);\n        }\n    }\n\n    private static HystrixCommandMetrics initMetrics(HystrixCommandMetrics fromConstructor, HystrixCommandGroupKey groupKey,\n                                                     HystrixThreadPoolKey threadPoolKey, HystrixCommandKey commandKey,\n                                                     HystrixCommandProperties properties) {\n        if (fromConstructor == null) {\n            return HystrixCommandMetrics.getInstance(commandKey, groupKey, threadPoolKey, properties);\n        } else {\n            return fromConstructor;\n        }\n    }\n\n    private static HystrixCircuitBreaker initCircuitBreaker(boolean enabled, HystrixCircuitBreaker fromConstructor,\n                                                            HystrixCommandGroupKey groupKey, HystrixCommandKey commandKey,\n                                                            HystrixCommandProperties properties, HystrixCommandMetrics metrics) {\n        if (enabled) {\n            if (fromConstructor == null) {\n                // get the default implementation of HystrixCircuitBreaker\n                return HystrixCircuitBreaker.Factory.getInstance(commandKey, groupKey, properties, metrics);\n            } else {\n                return fromConstructor;\n            }\n        } else {\n            return new NoOpCircuitBreaker();\n        }\n    }\n\n    private static HystrixCommandExecutionHook initExecutionHook(HystrixCommandExecutionHook fromConstructor) {\n        if (fromConstructor == null) {\n            return new ExecutionHookDeprecationWrapper(HystrixPlugins.getInstance().getCommandExecutionHook());\n        } else {\n            // used for unit testing\n            if (fromConstructor instanceof ExecutionHookDeprecationWrapper) {\n                return fromConstructor;\n            } else {\n                return new ExecutionHookDeprecationWrapper(fromConstructor);\n            }\n        }\n    }\n\n    private static HystrixThreadPool initThreadPool(HystrixThreadPool fromConstructor, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {\n        if (fromConstructor == null) {\n            // get the default implementation of HystrixThreadPool\n            return HystrixThreadPool.Factory.getInstance(threadPoolKey, threadPoolPropertiesDefaults);\n        } else {\n            return fromConstructor;\n        }\n    }\n\n    private static HystrixRequestLog initRequestLog(boolean enabled, HystrixConcurrencyStrategy concurrencyStrategy) {\n        if (enabled) {\n            /* store reference to request log regardless of which thread later hits it */\n            return HystrixRequestLog.getCurrentRequest(concurrencyStrategy);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Allow the Collapser to mark this command instance as being used for a collapsed request and how many requests were collapsed.\n     * \n     * @param sizeOfBatch number of commands in request batch\n     */\n    /* package */void markAsCollapsedCommand(HystrixCollapserKey collapserKey, int sizeOfBatch) {\n        eventNotifier.markEvent(HystrixEventType.COLLAPSED, this.commandKey);\n        executionResult = executionResult.markCollapsed(collapserKey, sizeOfBatch);\n    }\n\n    /**\n     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This eagerly starts execution of the command the same as {@link HystrixCommand#queue()} and {@link HystrixCommand#execute()}.\n     * <p>\n     * A lazy {@link Observable} can be obtained from {@link #toObservable()}.\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that executes and calls back with the result of command execution or a fallback if the command fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Observer#onError} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Observer#onError} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Observable<R> observe() {\n        // us a ReplaySubject to buffer the eagerly subscribed-to Observable\n        ReplaySubject<R> subject = ReplaySubject.create();\n        // eagerly kick off subscription\n        final Subscription sourceSubscription = toObservable().subscribe(subject);\n        // return the subject that can be subscribed to later while the execution has already started\n        return subject.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                sourceSubscription.unsubscribe();\n            }\n        });\n    }\n\n    protected abstract Observable<R> getExecutionObservable();\n\n    protected abstract Observable<R> getFallbackObservable();\n\n    /**\n     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This lazily starts execution of the command once the {@link Observable} is subscribed to.\n     * <p>\n     * An eager {@link Observable} can be obtained from {@link #observe()}.\n     * <p>\n     * See https://github.com/ReactiveX/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that executes and calls back with the result of command execution or a fallback if the command fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Observer#onError} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Observer#onError} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Observable<R> toObservable() {\n        final AbstractCommand<R> _cmd = this;\n\n        //doOnCompleted handler already did all of the SUCCESS work\n        //doOnError handler already did all of the FAILURE/TIMEOUT/REJECTION/BAD_REQUEST work\n        final Action0 terminateCommandCleanup = new Action0() {\n\n            @Override\n            public void call() {\n                if (_cmd.commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.TERMINAL)) {\n                    handleCommandEnd(false); //user code never ran\n                } else if (_cmd.commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.TERMINAL)) {\n                    handleCommandEnd(true); //user code did run\n                }\n            }\n        };\n\n        //mark the command as CANCELLED and store the latency (in addition to standard cleanup)\n        final Action0 unsubscribeCommandCleanup = new Action0() {\n            @Override\n            public void call() {\n                circuitBreaker.markNonSuccess();\n                if (_cmd.commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.UNSUBSCRIBED)) {\n                    if (!_cmd.executionResult.containsTerminalEvent()) {\n                        _cmd.eventNotifier.markEvent(HystrixEventType.CANCELLED, _cmd.commandKey);\n                        try {\n                            executionHook.onUnsubscribe(_cmd);\n                        } catch (Throwable hookEx) {\n                            logger.warn(\"Error calling HystrixCommandExecutionHook.onUnsubscribe\", hookEx);\n                        }\n                        _cmd.executionResultAtTimeOfCancellation = _cmd.executionResult\n                                .addEvent((int) (System.currentTimeMillis() - _cmd.commandStartTimestamp), HystrixEventType.CANCELLED);\n                    }\n                    handleCommandEnd(false); //user code never ran\n                } else if (_cmd.commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.UNSUBSCRIBED)) {\n                    if (!_cmd.executionResult.containsTerminalEvent()) {\n                        _cmd.eventNotifier.markEvent(HystrixEventType.CANCELLED, _cmd.commandKey);\n                        try {\n                            executionHook.onUnsubscribe(_cmd);\n                        } catch (Throwable hookEx) {\n                            logger.warn(\"Error calling HystrixCommandExecutionHook.onUnsubscribe\", hookEx);\n                        }\n                        _cmd.executionResultAtTimeOfCancellation = _cmd.executionResult\n                                .addEvent((int) (System.currentTimeMillis() - _cmd.commandStartTimestamp), HystrixEventType.CANCELLED);\n                    }\n                    handleCommandEnd(true); //user code did run\n                }\n            }\n        };\n\n        final Func0<Observable<R>> applyHystrixSemantics = new Func0<Observable<R>>() {\n            @Override\n            public Observable<R> call() {\n                if (commandState.get().equals(CommandState.UNSUBSCRIBED)) {\n                    return Observable.never();\n                }\n                return applyHystrixSemantics(_cmd);\n            }\n        };\n\n        final Func1<R, R> wrapWithAllOnNextHooks = new Func1<R, R>() {\n            @Override\n            public R call(R r) {\n                R afterFirstApplication = r;\n\n                try {\n                    afterFirstApplication = executionHook.onComplete(_cmd, r);\n                } catch (Throwable hookEx) {\n                    logger.warn(\"Error calling HystrixCommandExecutionHook.onComplete\", hookEx);\n                }\n\n                try {\n                    return executionHook.onEmit(_cmd, afterFirstApplication);\n                } catch (Throwable hookEx) {\n                    logger.warn(\"Error calling HystrixCommandExecutionHook.onEmit\", hookEx);\n                    return afterFirstApplication;\n                }\n            }\n        };\n\n        final Action0 fireOnCompletedHook = new Action0() {\n            @Override\n            public void call() {\n                try {\n                    executionHook.onSuccess(_cmd);\n                } catch (Throwable hookEx) {\n                    logger.warn(\"Error calling HystrixCommandExecutionHook.onSuccess\", hookEx);\n                }\n            }\n        };\n\n        return Observable.defer(new Func0<Observable<R>>() {\n            @Override\n            public Observable<R> call() {\n                 /* this is a stateful object so can only be used once */\n                if (!commandState.compareAndSet(CommandState.NOT_STARTED, CommandState.OBSERVABLE_CHAIN_CREATED)) {\n                    IllegalStateException ex = new IllegalStateException(\"This instance can only be executed once. Please instantiate a new instance.\");\n                    //TODO make a new error type for this\n                    throw new HystrixRuntimeException(FailureType.BAD_REQUEST_EXCEPTION, _cmd.getClass(), getLogMessagePrefix() + \" command executed multiple times - this is not permitted.\", ex, null);\n                }\n\n                commandStartTimestamp = System.currentTimeMillis();\n\n                if (properties.requestLogEnabled().get()) {\n                    // log this command execution regardless of what happened\n                    if (currentRequestLog != null) {\n                        currentRequestLog.addExecutedCommand(_cmd);\n                    }\n                }\n\n                final boolean requestCacheEnabled = isRequestCachingEnabled();\n                final String cacheKey = getCacheKey();\n\n                /* try from cache first */\n                if (requestCacheEnabled) {\n                    HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.get(cacheKey);\n                    if (fromCache != null) {\n                        isResponseFromCache = true;\n                        return handleRequestCacheHitAndEmitValues(fromCache, _cmd);\n                    }\n                }\n\n                Observable<R> hystrixObservable =\n                        Observable.defer(applyHystrixSemantics)\n                                .map(wrapWithAllOnNextHooks);\n\n                Observable<R> afterCache;\n\n                // put in cache\n                if (requestCacheEnabled && cacheKey != null) {\n                    // wrap it for caching\n                    HystrixCachedObservable<R> toCache = HystrixCachedObservable.from(hystrixObservable, _cmd);\n                    HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.putIfAbsent(cacheKey, toCache);\n                    if (fromCache != null) {\n                        // another thread beat us so we'll use the cached value instead\n                        toCache.unsubscribe();\n                        isResponseFromCache = true;\n                        return handleRequestCacheHitAndEmitValues(fromCache, _cmd);\n                    } else {\n                        // we just created an ObservableCommand so we cast and return it\n                        afterCache = toCache.toObservable();\n                    }\n                } else {\n                    afterCache = hystrixObservable;\n                }\n\n                return afterCache\n                        .doOnTerminate(terminateCommandCleanup)     // perform cleanup once (either on normal terminal state (this line), or unsubscribe (next line))\n                        .doOnUnsubscribe(unsubscribeCommandCleanup) // perform cleanup once\n                        .doOnCompleted(fireOnCompletedHook);\n            }\n        });\n    }\n\n    private Observable<R> applyHystrixSemantics(final AbstractCommand<R> _cmd) {\n        // mark that we're starting execution on the ExecutionHook\n        // if this hook throws an exception, then a fast-fail occurs with no fallback.  No state is left inconsistent\n        executionHook.onStart(_cmd);\n\n        /* determine if we're allowed to execute */\n        if (circuitBreaker.attemptExecution()) {\n            final TryableSemaphore executionSemaphore = getExecutionSemaphore();\n            final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);\n            final Action0 singleSemaphoreRelease = new Action0() {\n                @Override\n                public void call() {\n                    if (semaphoreHasBeenReleased.compareAndSet(false, true)) {\n                        executionSemaphore.release();\n                    }\n                }\n            };\n\n            final Action1<Throwable> markExceptionThrown = new Action1<Throwable>() {\n                @Override\n                public void call(Throwable t) {\n                    eventNotifier.markEvent(HystrixEventType.EXCEPTION_THROWN, commandKey);\n                }\n            };\n\n            if (executionSemaphore.tryAcquire()) {\n                try {\n                    /* used to track userThreadExecutionTime */\n                    executionResult = executionResult.setInvocationStartTime(System.currentTimeMillis());\n                    return executeCommandAndObserve(_cmd)\n                            .doOnError(markExceptionThrown)\n                            .doOnTerminate(singleSemaphoreRelease)\n                            .doOnUnsubscribe(singleSemaphoreRelease);\n                } catch (RuntimeException e) {\n                    return Observable.error(e);\n                }\n            } else {\n                return handleSemaphoreRejectionViaFallback();\n            }\n        } else {\n            return handleShortCircuitViaFallback();\n        }\n    }\n\n    abstract protected boolean commandIsScalar();\n\n    /**\n     * This decorates \"Hystrix\" functionality around the run() Observable.\n     *\n     * @return R\n     */\n    private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {\n        final HystrixRequestContext currentRequestContext = HystrixRequestContext.getContextForCurrentThread();\n\n        final Action1<R> markEmits = new Action1<R>() {\n            @Override\n            public void call(R r) {\n                if (shouldOutputOnNextEvents()) {\n                    executionResult = executionResult.addEvent(HystrixEventType.EMIT);\n                    eventNotifier.markEvent(HystrixEventType.EMIT, commandKey);\n                }\n                if (commandIsScalar()) {\n                    long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n                    eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);\n                    executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);\n                    eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());\n                    circuitBreaker.markSuccess();\n                }\n            }\n        };\n\n        final Action0 markOnCompleted = new Action0() {\n            @Override\n            public void call() {\n                if (!commandIsScalar()) {\n                    long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n                    eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);\n                    executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);\n                    eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());\n                    circuitBreaker.markSuccess();\n                }\n            }\n        };\n\n        final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {\n            @Override\n            public Observable<R> call(Throwable t) {\n                circuitBreaker.markNonSuccess();\n                Exception e = getExceptionFromThrowable(t);\n                executionResult = executionResult.setExecutionException(e);\n                if (e instanceof RejectedExecutionException) {\n                    return handleThreadPoolRejectionViaFallback(e);\n                } else if (t instanceof HystrixTimeoutException) {\n                    return handleTimeoutViaFallback();\n                } else if (t instanceof HystrixBadRequestException) {\n                    return handleBadRequestByEmittingError(e);\n                } else {\n                    /*\n                     * Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.\n                     */\n                    if (e instanceof HystrixBadRequestException) {\n                        eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);\n                        return Observable.error(e);\n                    }\n\n                    return handleFailureViaFallback(e);\n                }\n            }\n        };\n\n        final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() {\n            @Override\n            public void call(Notification<? super R> rNotification) {\n                setRequestContextIfNeeded(currentRequestContext);\n            }\n        };\n\n        Observable<R> execution;\n        if (properties.executionTimeoutEnabled().get()) {\n            execution = executeCommandWithSpecifiedIsolation(_cmd)\n                    .lift(new HystrixObservableTimeoutOperator<R>(_cmd));\n        } else {\n            execution = executeCommandWithSpecifiedIsolation(_cmd);\n        }\n\n        return execution.doOnNext(markEmits)\n                .doOnCompleted(markOnCompleted)\n                .onErrorResumeNext(handleFallback)\n                .doOnEach(setRequestContext);\n    }\n\n    private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {\n        if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {\n            // mark that we are executing in a thread (even if we end up being rejected we still were a THREAD execution and not SEMAPHORE)\n            return Observable.defer(new Func0<Observable<R>>() {\n                @Override\n                public Observable<R> call() {\n                    executionResult = executionResult.setExecutionOccurred();\n                    if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {\n                        return Observable.error(new IllegalStateException(\"execution attempted while in state : \" + commandState.get().name()));\n                    }\n\n                    metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.THREAD);\n\n                    if (isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT) {\n                        // the command timed out in the wrapping thread so we will return immediately\n                        // and not increment any of the counters below or other such logic\n                        return Observable.error(new RuntimeException(\"timed out before executing run()\"));\n                    }\n                    if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.STARTED)) {\n                        //we have not been unsubscribed, so should proceed\n                        HystrixCounters.incrementGlobalConcurrentThreads();\n                        threadPool.markThreadExecution();\n                        // store the command that is being run\n                        endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());\n                        executionResult = executionResult.setExecutedInThread();\n                        /**\n                         * If any of these hooks throw an exception, then it appears as if the actual execution threw an error\n                         */\n                        try {\n                            executionHook.onThreadStart(_cmd);\n                            executionHook.onRunStart(_cmd);\n                            executionHook.onExecutionStart(_cmd);\n                            return getUserExecutionObservable(_cmd);\n                        } catch (Throwable ex) {\n                            return Observable.error(ex);\n                        }\n                    } else {\n                        //command has already been unsubscribed, so return immediately\n                        return Observable.empty();\n                    }\n                }\n            }).doOnTerminate(new Action0() {\n                @Override\n                public void call() {\n                    if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.TERMINAL)) {\n                        handleThreadEnd(_cmd);\n                    }\n                    if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.TERMINAL)) {\n                        //if it was never started and received terminal, then no need to clean up (I don't think this is possible)\n                    }\n                    //if it was unsubscribed, then other cleanup handled it\n                }\n            }).doOnUnsubscribe(new Action0() {\n                @Override\n                public void call() {\n                    if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.UNSUBSCRIBED)) {\n                        handleThreadEnd(_cmd);\n                    }\n                    if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.UNSUBSCRIBED)) {\n                        //if it was never started and was cancelled, then no need to clean up\n                    }\n                    //if it was terminal, then other cleanup handled it\n                }\n            }).subscribeOn(threadPool.getScheduler(new Func0<Boolean>() {\n                @Override\n                public Boolean call() {\n                    return properties.executionIsolationThreadInterruptOnTimeout().get() && _cmd.isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT;\n                }\n            }));\n        } else {\n            return Observable.defer(new Func0<Observable<R>>() {\n                @Override\n                public Observable<R> call() {\n                    executionResult = executionResult.setExecutionOccurred();\n                    if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {\n                        return Observable.error(new IllegalStateException(\"execution attempted while in state : \" + commandState.get().name()));\n                    }\n\n                    metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.SEMAPHORE);\n                    // semaphore isolated\n                    // store the command that is being run\n                    endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());\n                    try {\n                        executionHook.onRunStart(_cmd);\n                        executionHook.onExecutionStart(_cmd);\n                        return getUserExecutionObservable(_cmd);  //the getUserExecutionObservable method already wraps sync exceptions, so this shouldn't throw\n                    } catch (Throwable ex) {\n                        //If the above hooks throw, then use that as the result of the run method\n                        return Observable.error(ex);\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * Execute <code>getFallback()</code> within protection of a semaphore that limits number of concurrent executions.\n     * <p>\n     * Fallback implementations shouldn't perform anything that can be blocking, but we protect against it anyways in case someone doesn't abide by the contract.\n     * <p>\n     * If something in the <code>getFallback()</code> implementation is latent (such as a network call) then the semaphore will cause us to start rejecting requests rather than allowing potentially\n     * all threads to pile up and block.\n     *\n     * @return K\n     * @throws UnsupportedOperationException\n     *             if getFallback() not implemented\n     * @throws HystrixRuntimeException\n     *             if getFallback() fails (throws an Exception) or is rejected by the semaphore\n     */\n    private Observable<R> getFallbackOrThrowException(final AbstractCommand<R> _cmd, final HystrixEventType eventType, final FailureType failureType, final String message, final Exception originalException) {\n        final HystrixRequestContext requestContext = HystrixRequestContext.getContextForCurrentThread();\n        long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n        // record the executionResult\n        // do this before executing fallback so it can be queried from within getFallback (see See https://github.com/Netflix/Hystrix/pull/144)\n        executionResult = executionResult.addEvent((int) latency, eventType);\n\n        if (isUnrecoverable(originalException)) {\n            logger.error(\"Unrecoverable Error for HystrixCommand so will throw HystrixRuntimeException and not apply fallback. \", originalException);\n\n            /* executionHook for all errors */\n            Exception e = wrapWithOnErrorHook(failureType, originalException);\n            return Observable.error(new HystrixRuntimeException(failureType, this.getClass(), getLogMessagePrefix() + \" \" + message + \" and encountered unrecoverable error.\", e, null));\n        } else {\n            if (isRecoverableError(originalException)) {\n                logger.warn(\"Recovered from java.lang.Error by serving Hystrix fallback\", originalException);\n            }\n\n            if (properties.fallbackEnabled().get()) {\n                /* fallback behavior is permitted so attempt */\n\n                final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() {\n                    @Override\n                    public void call(Notification<? super R> rNotification) {\n                        setRequestContextIfNeeded(requestContext);\n                    }\n                };\n\n                final Action1<R> markFallbackEmit = new Action1<R>() {\n                    @Override\n                    public void call(R r) {\n                        if (shouldOutputOnNextEvents()) {\n                            executionResult = executionResult.addEvent(HystrixEventType.FALLBACK_EMIT);\n                            eventNotifier.markEvent(HystrixEventType.FALLBACK_EMIT, commandKey);\n                        }\n                    }\n                };\n\n                final Action0 markFallbackCompleted = new Action0() {\n                    @Override\n                    public void call() {\n                        long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n                        eventNotifier.markEvent(HystrixEventType.FALLBACK_SUCCESS, commandKey);\n                        executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_SUCCESS);\n                    }\n                };\n\n                final Func1<Throwable, Observable<R>> handleFallbackError = new Func1<Throwable, Observable<R>>() {\n                    @Override\n                    public Observable<R> call(Throwable t) {\n                        /* executionHook for all errors */\n                        Exception e = wrapWithOnErrorHook(failureType, originalException);\n                        Exception fe = getExceptionFromThrowable(t);\n\n                        long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n                        Exception toEmit;\n\n                        if (fe instanceof UnsupportedOperationException) {\n                            logger.debug(\"No fallback for HystrixCommand. \", fe); // debug only since we're throwing the exception and someone higher will do something with it\n                            eventNotifier.markEvent(HystrixEventType.FALLBACK_MISSING, commandKey);\n                            executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_MISSING);\n\n                            toEmit = new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + \" \" + message + \" and no fallback available.\", e, fe);\n                        } else {\n                            logger.debug(\"HystrixCommand execution \" + failureType.name() + \" and fallback failed.\", fe);\n                            eventNotifier.markEvent(HystrixEventType.FALLBACK_FAILURE, commandKey);\n                            executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_FAILURE);\n\n                            toEmit = new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + \" \" + message + \" and fallback failed.\", e, fe);\n                        }\n\n                        // NOTE: we're suppressing fallback exception here\n                        if (shouldNotBeWrapped(originalException)) {\n                            return Observable.error(e);\n                        }\n\n                        return Observable.error(toEmit);\n                    }\n                };\n\n                final TryableSemaphore fallbackSemaphore = getFallbackSemaphore();\n                final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);\n                final Action0 singleSemaphoreRelease = new Action0() {\n                    @Override\n                    public void call() {\n                        if (semaphoreHasBeenReleased.compareAndSet(false, true)) {\n                            fallbackSemaphore.release();\n                        }\n                    }\n                };\n\n                Observable<R> fallbackExecutionChain;\n\n                // acquire a permit\n                if (fallbackSemaphore.tryAcquire()) {\n                    try {\n                        if (isFallbackUserDefined()) {\n                            executionHook.onFallbackStart(this);\n                            fallbackExecutionChain = getFallbackObservable();\n                        } else {\n                            //same logic as above without the hook invocation\n                            fallbackExecutionChain = getFallbackObservable();\n                        }\n                    } catch (Throwable ex) {\n                        //If hook or user-fallback throws, then use that as the result of the fallback lookup\n                        fallbackExecutionChain = Observable.error(ex);\n                    }\n\n                    return fallbackExecutionChain\n                            .doOnEach(setRequestContext)\n                            .lift(new FallbackHookApplication(_cmd))\n                            .lift(new DeprecatedOnFallbackHookApplication(_cmd))\n                            .doOnNext(markFallbackEmit)\n                            .doOnCompleted(markFallbackCompleted)\n                            .onErrorResumeNext(handleFallbackError)\n                            .doOnTerminate(singleSemaphoreRelease)\n                            .doOnUnsubscribe(singleSemaphoreRelease);\n                } else {\n                   return handleFallbackRejectionByEmittingError();\n                }\n            } else {\n                return handleFallbackDisabledByEmittingError(originalException, failureType, message);\n            }\n        }\n    }\n\n    private Observable<R> getUserExecutionObservable(final AbstractCommand<R> _cmd) {\n        Observable<R> userObservable;\n\n        try {\n            userObservable = getExecutionObservable();\n        } catch (Throwable ex) {\n            // the run() method is a user provided implementation so can throw instead of using Observable.onError\n            // so we catch it here and turn it into Observable.error\n            userObservable = Observable.error(ex);\n        }\n\n        return userObservable\n                .lift(new ExecutionHookApplication(_cmd))\n                .lift(new DeprecatedOnRunHookApplication(_cmd));\n    }\n\n    private Observable<R> handleRequestCacheHitAndEmitValues(final HystrixCommandResponseFromCache<R> fromCache, final AbstractCommand<R> _cmd) {\n        try {\n            executionHook.onCacheHit(this);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onCacheHit\", hookEx);\n        }\n\n        return fromCache.toObservableWithStateCopiedInto(this)\n                .doOnTerminate(new Action0() {\n                    @Override\n                    public void call() {\n                        if (commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.TERMINAL)) {\n                            cleanUpAfterResponseFromCache(false); //user code never ran\n                        } else if (commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.TERMINAL)) {\n                            cleanUpAfterResponseFromCache(true); //user code did run\n                        }\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        if (commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.UNSUBSCRIBED)) {\n                            cleanUpAfterResponseFromCache(false); //user code never ran\n                        } else if (commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.UNSUBSCRIBED)) {\n                            cleanUpAfterResponseFromCache(true); //user code did run\n                        }\n                    }\n                });\n    }\n\n    private void cleanUpAfterResponseFromCache(boolean commandExecutionStarted) {\n        Reference<TimerListener> tl = timeoutTimer.get();\n        if (tl != null) {\n            tl.clear();\n        }\n\n        final long latency = System.currentTimeMillis() - commandStartTimestamp;\n        executionResult = executionResult\n                .addEvent(-1, HystrixEventType.RESPONSE_FROM_CACHE)\n                .markUserThreadCompletion(latency)\n                .setNotExecutedInThread();\n        ExecutionResult cacheOnlyForMetrics = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE)\n                .markUserThreadCompletion(latency);\n        metrics.markCommandDone(cacheOnlyForMetrics, commandKey, threadPoolKey, commandExecutionStarted);\n        eventNotifier.markEvent(HystrixEventType.RESPONSE_FROM_CACHE, commandKey);\n    }\n\n    private void handleCommandEnd(boolean commandExecutionStarted) {\n        Reference<TimerListener> tl = timeoutTimer.get();\n        if (tl != null) {\n            tl.clear();\n        }\n\n        long userThreadLatency = System.currentTimeMillis() - commandStartTimestamp;\n        executionResult = executionResult.markUserThreadCompletion((int) userThreadLatency);\n        if (executionResultAtTimeOfCancellation == null) {\n            metrics.markCommandDone(executionResult, commandKey, threadPoolKey, commandExecutionStarted);\n        } else {\n            metrics.markCommandDone(executionResultAtTimeOfCancellation, commandKey, threadPoolKey, commandExecutionStarted);\n        }\n\n        if (endCurrentThreadExecutingCommand != null) {\n            endCurrentThreadExecutingCommand.call();\n        }\n    }\n\n    private Observable<R> handleSemaphoreRejectionViaFallback() {\n        Exception semaphoreRejectionException = new RuntimeException(\"could not acquire a semaphore for execution\");\n        executionResult = executionResult.setExecutionException(semaphoreRejectionException);\n        eventNotifier.markEvent(HystrixEventType.SEMAPHORE_REJECTED, commandKey);\n        logger.debug(\"HystrixCommand Execution Rejection by Semaphore.\"); // debug only since we're throwing the exception and someone higher will do something with it\n        // retrieve a fallback or throw an exception if no fallback available\n        return getFallbackOrThrowException(this, HystrixEventType.SEMAPHORE_REJECTED, FailureType.REJECTED_SEMAPHORE_EXECUTION,\n                \"could not acquire a semaphore for execution\", semaphoreRejectionException);\n    }\n\n    private Observable<R> handleShortCircuitViaFallback() {\n        // record that we are returning a short-circuited fallback\n        eventNotifier.markEvent(HystrixEventType.SHORT_CIRCUITED, commandKey);\n        // short-circuit and go directly to fallback (or throw an exception if no fallback implemented)\n        Exception shortCircuitException = new RuntimeException(\"Hystrix circuit short-circuited and is OPEN\");\n        executionResult = executionResult.setExecutionException(shortCircuitException);\n        try {\n            return getFallbackOrThrowException(this, HystrixEventType.SHORT_CIRCUITED, FailureType.SHORTCIRCUIT,\n                    \"short-circuited\", shortCircuitException);\n        } catch (Exception e) {\n            return Observable.error(e);\n        }\n    }\n\n    private Observable<R> handleThreadPoolRejectionViaFallback(Exception underlying) {\n        eventNotifier.markEvent(HystrixEventType.THREAD_POOL_REJECTED, commandKey);\n        threadPool.markThreadRejection();\n        // use a fallback instead (or throw exception if not implemented)\n        return getFallbackOrThrowException(this, HystrixEventType.THREAD_POOL_REJECTED, FailureType.REJECTED_THREAD_EXECUTION, \"could not be queued for execution\", underlying);\n    }\n\n    private Observable<R> handleTimeoutViaFallback() {\n        return getFallbackOrThrowException(this, HystrixEventType.TIMEOUT, FailureType.TIMEOUT, \"timed-out\", new TimeoutException());\n    }\n\n    private Observable<R> handleBadRequestByEmittingError(Exception underlying) {\n        Exception toEmit = underlying;\n\n        try {\n            long executionLatency = System.currentTimeMillis() - executionResult.getStartTimestamp();\n            eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);\n            executionResult = executionResult.addEvent((int) executionLatency, HystrixEventType.BAD_REQUEST);\n            Exception decorated = executionHook.onError(this, FailureType.BAD_REQUEST_EXCEPTION, underlying);\n\n            if (decorated instanceof HystrixBadRequestException) {\n                toEmit = decorated;\n            } else {\n                logger.warn(\"ExecutionHook.onError returned an exception that was not an instance of HystrixBadRequestException so will be ignored.\", decorated);\n            }\n        } catch (Exception hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onError\", hookEx);\n        }\n        /*\n         * HystrixBadRequestException is treated differently and allowed to propagate without any stats tracking or fallback logic\n         */\n        return Observable.error(toEmit);\n    }\n\n    private Observable<R> handleFailureViaFallback(Exception underlying) {\n        /**\n         * All other error handling\n         */\n        logger.debug(\"Error executing HystrixCommand.run(). Proceeding to fallback logic ...\", underlying);\n\n        // report failure\n        eventNotifier.markEvent(HystrixEventType.FAILURE, commandKey);\n\n        // record the exception\n        executionResult = executionResult.setException(underlying);\n        return getFallbackOrThrowException(this, HystrixEventType.FAILURE, FailureType.COMMAND_EXCEPTION, \"failed\", underlying);\n    }\n\n    private Observable<R> handleFallbackRejectionByEmittingError() {\n        long latencyWithFallback = System.currentTimeMillis() - executionResult.getStartTimestamp();\n        eventNotifier.markEvent(HystrixEventType.FALLBACK_REJECTION, commandKey);\n        executionResult = executionResult.addEvent((int) latencyWithFallback, HystrixEventType.FALLBACK_REJECTION);\n        logger.debug(\"HystrixCommand Fallback Rejection.\"); // debug only since we're throwing the exception and someone higher will do something with it\n        // if we couldn't acquire a permit, we \"fail fast\" by throwing an exception\n        return Observable.error(new HystrixRuntimeException(FailureType.REJECTED_SEMAPHORE_FALLBACK, this.getClass(), getLogMessagePrefix() + \" fallback execution rejected.\", null, null));\n    }\n\n    private Observable<R> handleFallbackDisabledByEmittingError(Exception underlying, FailureType failureType, String message) {\n        /* fallback is disabled so throw HystrixRuntimeException */\n        logger.debug(\"Fallback disabled for HystrixCommand so will throw HystrixRuntimeException. \", underlying); // debug only since we're throwing the exception and someone higher will do something with it\n        eventNotifier.markEvent(HystrixEventType.FALLBACK_DISABLED, commandKey);\n\n        /* executionHook for all errors */\n        Exception wrapped = wrapWithOnErrorHook(failureType, underlying);\n        return Observable.error(new HystrixRuntimeException(failureType, this.getClass(), getLogMessagePrefix() + \" \" + message + \" and fallback disabled.\", wrapped, null));\n    }\n\n    protected boolean shouldNotBeWrapped(Throwable underlying) {\n        return underlying instanceof ExceptionNotWrappedByHystrix;\n    }\n\n    /**\n     * Returns true iff the t was caused by a java.lang.Error that is unrecoverable.  Note: not all java.lang.Errors are unrecoverable.\n     * @see <a href=\"https://github.com/Netflix/Hystrix/issues/713\"></a> for more context\n     * Solution taken from <a href=\"https://github.com/ReactiveX/RxJava/issues/748\"></a>\n     *\n     * The specific set of Error that are considered unrecoverable are:\n     * <ul>\n     * <li>{@code StackOverflowError}</li>\n     * <li>{@code VirtualMachineError}</li>\n     * <li>{@code ThreadDeath}</li>\n     * <li>{@code LinkageError}</li>\n     * </ul>\n     *\n     * @param t throwable to check\n     * @return true iff the t was caused by a java.lang.Error that is unrecoverable\n     */\n    private boolean isUnrecoverable(Throwable t) {\n        if (t != null && t.getCause() != null) {\n            Throwable cause = t.getCause();\n            if (cause instanceof StackOverflowError) {\n                return true;\n            } else if (cause instanceof VirtualMachineError) {\n                return true;\n            } else if (cause instanceof ThreadDeath) {\n                return true;\n            } else if (cause instanceof LinkageError) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private boolean isRecoverableError(Throwable t) {\n        if (t != null && t.getCause() != null) {\n            Throwable cause = t.getCause();\n            if (cause instanceof java.lang.Error) {\n                return !isUnrecoverable(t);\n            }\n        }\n        return false;\n    }\n\n    protected void handleThreadEnd(AbstractCommand<R> _cmd) {\n        HystrixCounters.decrementGlobalConcurrentThreads();\n        threadPool.markThreadCompletion();\n        try {\n            executionHook.onThreadComplete(_cmd);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onThreadComplete\", hookEx);\n        }\n    }\n\n    /**\n     *\n     * @return if onNext events should be reported on\n     * This affects {@link HystrixRequestLog}, and {@link HystrixEventNotifier} currently.\n     */\n    protected boolean shouldOutputOnNextEvents() {\n        return false;\n    }\n\n    private static class HystrixObservableTimeoutOperator<R> implements Operator<R, R> {\n\n        final AbstractCommand<R> originalCommand;\n\n        public HystrixObservableTimeoutOperator(final AbstractCommand<R> originalCommand) {\n            this.originalCommand = originalCommand;\n        }\n\n        @Override\n        public Subscriber<? super R> call(final Subscriber<? super R> child) {\n            final CompositeSubscription s = new CompositeSubscription();\n            // if the child unsubscribes we unsubscribe our parent as well\n            child.add(s);\n\n            //capture the HystrixRequestContext upfront so that we can use it in the timeout thread later\n            final HystrixRequestContext hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();\n\n            TimerListener listener = new TimerListener() {\n\n                @Override\n                public void tick() {\n                    // if we can go from NOT_EXECUTED to TIMED_OUT then we do the timeout codepath\n                    // otherwise it means we lost a race and the run() execution completed or did not start\n                    if (originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.TIMED_OUT)) {\n                        // report timeout failure\n                        originalCommand.eventNotifier.markEvent(HystrixEventType.TIMEOUT, originalCommand.commandKey);\n\n                        // shut down the original request\n                        s.unsubscribe();\n\n                        final HystrixContextRunnable timeoutRunnable = new HystrixContextRunnable(originalCommand.concurrencyStrategy, hystrixRequestContext, new Runnable() {\n\n                            @Override\n                            public void run() {\n                                child.onError(new HystrixTimeoutException());\n                            }\n                        });\n\n\n                        timeoutRunnable.run();\n                        //if it did not start, then we need to mark a command start for concurrency metrics, and then issue the timeout\n                    }\n                }\n\n                @Override\n                public int getIntervalTimeInMilliseconds() {\n                    return originalCommand.properties.executionTimeoutInMilliseconds().get();\n                }\n            };\n\n            final Reference<TimerListener> tl = HystrixTimer.getInstance().addTimerListener(listener);\n\n            // set externally so execute/queue can see this\n            originalCommand.timeoutTimer.set(tl);\n\n            /**\n             * If this subscriber receives values it means the parent succeeded/completed\n             */\n            Subscriber<R> parent = new Subscriber<R>() {\n\n                @Override\n                public void onCompleted() {\n                    if (isNotTimedOut()) {\n                        // stop timer and pass notification through\n                        tl.clear();\n                        child.onCompleted();\n                    }\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    if (isNotTimedOut()) {\n                        // stop timer and pass notification through\n                        tl.clear();\n                        child.onError(e);\n                    }\n                }\n\n                @Override\n                public void onNext(R v) {\n                    if (isNotTimedOut()) {\n                        child.onNext(v);\n                    }\n                }\n\n                private boolean isNotTimedOut() {\n                    // if already marked COMPLETED (by onNext) or succeeds in setting to COMPLETED\n                    return originalCommand.isCommandTimedOut.get() == TimedOutStatus.COMPLETED ||\n                            originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.COMPLETED);\n                }\n\n            };\n\n            // if s is unsubscribed we want to unsubscribe the parent\n            s.add(parent);\n\n            return parent;\n        }\n\n    }\n\n    private static void setRequestContextIfNeeded(final HystrixRequestContext currentRequestContext) {\n        if (!HystrixRequestContext.isCurrentThreadInitialized()) {\n            // even if the user Observable doesn't have context we want it set for chained operators\n            HystrixRequestContext.setContextOnCurrentThread(currentRequestContext);\n        }\n    }\n\n    /**\n     * Get the TryableSemaphore this HystrixCommand should use if a fallback occurs.\n     * \n     * @return TryableSemaphore\n     */\n    protected TryableSemaphore getFallbackSemaphore() {\n        if (fallbackSemaphoreOverride == null) {\n            TryableSemaphore _s = fallbackSemaphorePerCircuit.get(commandKey.name());\n            if (_s == null) {\n                // we didn't find one cache so setup\n                fallbackSemaphorePerCircuit.putIfAbsent(commandKey.name(), new TryableSemaphoreActual(properties.fallbackIsolationSemaphoreMaxConcurrentRequests()));\n                // assign whatever got set (this or another thread)\n                return fallbackSemaphorePerCircuit.get(commandKey.name());\n            } else {\n                return _s;\n            }\n        } else {\n            return fallbackSemaphoreOverride;\n        }\n    }\n\n    /**\n     * Get the TryableSemaphore this HystrixCommand should use for execution if not running in a separate thread.\n     * \n     * @return TryableSemaphore\n     */\n    protected TryableSemaphore getExecutionSemaphore() {\n        if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.SEMAPHORE) {\n            if (executionSemaphoreOverride == null) {\n                TryableSemaphore _s = executionSemaphorePerCircuit.get(commandKey.name());\n                if (_s == null) {\n                    // we didn't find one cache so setup\n                    executionSemaphorePerCircuit.putIfAbsent(commandKey.name(), new TryableSemaphoreActual(properties.executionIsolationSemaphoreMaxConcurrentRequests()));\n                    // assign whatever got set (this or another thread)\n                    return executionSemaphorePerCircuit.get(commandKey.name());\n                } else {\n                    return _s;\n                }\n            } else {\n                return executionSemaphoreOverride;\n            }\n        } else {\n            // return NoOp implementation since we're not using SEMAPHORE isolation\n            return TryableSemaphoreNoOp.DEFAULT;\n        }\n    }\n\n    /**\n     * Each concrete implementation of AbstractCommand should return the name of the fallback method as a String\n     * This will be used to determine if the fallback \"exists\" for firing the onFallbackStart/onFallbackError hooks\n     * @deprecated This functionality is replaced by {@link #isFallbackUserDefined}, which is less implementation-aware\n     * @return method name of fallback\n     */\n    @Deprecated\n    protected abstract String getFallbackMethodName();\n\n    protected abstract boolean isFallbackUserDefined();\n\n    /**\n     * @return {@link HystrixCommandGroupKey} used to group together multiple {@link AbstractCommand} objects.\n     *         <p>\n     *         The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace with,\n     *         common business purpose etc.\n     */\n    public HystrixCommandGroupKey getCommandGroup() {\n        return commandGroup;\n    }\n\n    /**\n     * @return {@link HystrixCommandKey} identifying this command instance for statistics, circuit-breaker, properties, etc.\n     */\n    public HystrixCommandKey getCommandKey() {\n        return commandKey;\n    }\n\n    /**\n     * @return {@link HystrixThreadPoolKey} identifying which thread-pool this command uses (when configured to run on separate threads via\n     *         {@link HystrixCommandProperties#executionIsolationStrategy()}).\n     */\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    /* package */HystrixCircuitBreaker getCircuitBreaker() {\n        return circuitBreaker;\n    }\n\n    /**\n     * The {@link HystrixCommandMetrics} associated with this {@link AbstractCommand} instance.\n     *\n     * @return HystrixCommandMetrics\n     */\n    public HystrixCommandMetrics getMetrics() {\n        return metrics;\n    }\n\n    /**\n     * The {@link HystrixCommandProperties} associated with this {@link AbstractCommand} instance.\n     * \n     * @return HystrixCommandProperties\n     */\n    public HystrixCommandProperties getProperties() {\n        return properties;\n    }\n\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n    /* Operators that implement hook application */\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n\n    private class ExecutionHookApplication implements Operator<R, R> {\n        private final HystrixInvokable<R> cmd;\n\n        ExecutionHookApplication(HystrixInvokable<R> cmd) {\n            this.cmd = cmd;\n        }\n\n        @Override\n        public Subscriber<? super R> call(final Subscriber<? super R> subscriber) {\n            return new Subscriber<R>(subscriber) {\n                @Override\n                public void onCompleted() {\n                    try {\n                        executionHook.onExecutionSuccess(cmd);\n                    } catch (Throwable hookEx) {\n                        logger.warn(\"Error calling HystrixCommandExecutionHook.onExecutionSuccess\", hookEx);\n                    }\n                    subscriber.onCompleted();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    Exception wrappedEx = wrapWithOnExecutionErrorHook(e);\n                    subscriber.onError(wrappedEx);\n                }\n\n                @Override\n                public void onNext(R r) {\n                    R wrappedValue = wrapWithOnExecutionEmitHook(r);\n                    subscriber.onNext(wrappedValue);\n                }\n            };\n        }\n    }\n\n    private class FallbackHookApplication implements Operator<R, R> {\n        private final HystrixInvokable<R> cmd;\n\n        FallbackHookApplication(HystrixInvokable<R> cmd) {\n            this.cmd = cmd;\n        }\n\n        @Override\n        public Subscriber<? super R> call(final Subscriber<? super R> subscriber) {\n            return new Subscriber<R>(subscriber) {\n                @Override\n                public void onCompleted() {\n                    try {\n                        executionHook.onFallbackSuccess(cmd);\n                    } catch (Throwable hookEx) {\n                        logger.warn(\"Error calling HystrixCommandExecutionHook.onFallbackSuccess\", hookEx);\n                    }\n                    subscriber.onCompleted();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    Exception wrappedEx = wrapWithOnFallbackErrorHook(e);\n                    subscriber.onError(wrappedEx);\n                }\n\n                @Override\n                public void onNext(R r) {\n                    R wrappedValue = wrapWithOnFallbackEmitHook(r);\n                    subscriber.onNext(wrappedValue);\n                }\n            };\n        }\n    }\n\n    @Deprecated //separated out to make it cleanly removable\n    private class DeprecatedOnRunHookApplication implements Operator<R, R> {\n\n        private final HystrixInvokable<R> cmd;\n\n        DeprecatedOnRunHookApplication(HystrixInvokable<R> cmd) {\n            this.cmd = cmd;\n        }\n\n        @Override\n        public Subscriber<? super R> call(final Subscriber<? super R> subscriber) {\n            return new Subscriber<R>(subscriber) {\n                @Override\n                public void onCompleted() {\n                    subscriber.onCompleted();\n                }\n\n                @Override\n                public void onError(Throwable t) {\n                    Exception e = getExceptionFromThrowable(t);\n                    try {\n                        Exception wrappedEx = executionHook.onRunError(cmd, e);\n                        subscriber.onError(wrappedEx);\n                    } catch (Throwable hookEx) {\n                        logger.warn(\"Error calling HystrixCommandExecutionHook.onRunError\", hookEx);\n                        subscriber.onError(e);\n                    }\n                }\n\n                @Override\n                public void onNext(R r) {\n                    try {\n                        R wrappedValue = executionHook.onRunSuccess(cmd, r);\n                        subscriber.onNext(wrappedValue);\n                    } catch (Throwable hookEx) {\n                        logger.warn(\"Error calling HystrixCommandExecutionHook.onRunSuccess\", hookEx);\n                        subscriber.onNext(r);\n                    }\n                }\n            };\n        }\n    }\n\n    @Deprecated //separated out to make it cleanly removable\n    private class DeprecatedOnFallbackHookApplication implements Operator<R, R> {\n\n        private final HystrixInvokable<R> cmd;\n\n        DeprecatedOnFallbackHookApplication(HystrixInvokable<R> cmd) {\n            this.cmd = cmd;\n        }\n\n        @Override\n        public Subscriber<? super R> call(final Subscriber<? super R> subscriber) {\n            return new Subscriber<R>(subscriber) {\n                @Override\n                public void onCompleted() {\n                    subscriber.onCompleted();\n                }\n\n                @Override\n                public void onError(Throwable t) {\n                    //no need to call a hook here.  FallbackHookApplication is already calling the proper and non-deprecated hook\n                    subscriber.onError(t);\n                }\n\n                @Override\n                public void onNext(R r) {\n                    try {\n                        R wrappedValue = executionHook.onFallbackSuccess(cmd, r);\n                        subscriber.onNext(wrappedValue);\n                    } catch (Throwable hookEx) {\n                        logger.warn(\"Error calling HystrixCommandExecutionHook.onFallbackSuccess\", hookEx);\n                        subscriber.onNext(r);\n                    }\n                }\n            };\n        }\n    }\n\n    private Exception wrapWithOnExecutionErrorHook(Throwable t) {\n        Exception e = getExceptionFromThrowable(t);\n        try {\n            return executionHook.onExecutionError(this, e);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onExecutionError\", hookEx);\n            return e;\n        }\n    }\n\n    private Exception wrapWithOnFallbackErrorHook(Throwable t) {\n        Exception e = getExceptionFromThrowable(t);\n        try {\n            if (isFallbackUserDefined()) {\n                return executionHook.onFallbackError(this, e);\n            } else {\n                return e;\n            }\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onFallbackError\", hookEx);\n            return e;\n        }\n    }\n\n    private Exception wrapWithOnErrorHook(FailureType failureType, Throwable t) {\n        Exception e = getExceptionFromThrowable(t);\n        try {\n            return executionHook.onError(this, failureType, e);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onError\", hookEx);\n            return e;\n        }\n    }\n\n    private R wrapWithOnExecutionEmitHook(R r) {\n        try {\n            return executionHook.onExecutionEmit(this, r);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onExecutionEmit\", hookEx);\n            return r;\n        }\n    }\n\n    private R wrapWithOnFallbackEmitHook(R r) {\n        try {\n            return executionHook.onFallbackEmit(this, r);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onFallbackEmit\", hookEx);\n            return r;\n        }\n    }\n\n    private R wrapWithOnEmitHook(R r) {\n        try {\n            return executionHook.onEmit(this, r);\n        } catch (Throwable hookEx) {\n            logger.warn(\"Error calling HystrixCommandExecutionHook.onEmit\", hookEx);\n            return r;\n        }\n    }\n\n    /**\n     * Take an Exception and determine whether to throw it, its cause or a new HystrixRuntimeException.\n     * <p>\n     * This will only throw an HystrixRuntimeException, HystrixBadRequestException, IllegalStateException\n     * or any exception that implements ExceptionNotWrappedByHystrix.\n     * \n     * @param e initial exception\n     * @return HystrixRuntimeException, HystrixBadRequestException or IllegalStateException\n     */\n    protected Throwable decomposeException(Exception e) {\n        if (e instanceof IllegalStateException) {\n            return (IllegalStateException) e;\n        }\n        if (e instanceof HystrixBadRequestException) {\n            if (shouldNotBeWrapped(e.getCause())) {\n                return e.getCause();\n            }\n            return (HystrixBadRequestException) e;\n        }\n        if (e.getCause() instanceof HystrixBadRequestException) {\n            if(shouldNotBeWrapped(e.getCause().getCause())) {\n                return e.getCause().getCause();\n            }\n            return (HystrixBadRequestException) e.getCause();\n        }\n        if (e instanceof HystrixRuntimeException) {\n            return (HystrixRuntimeException) e;\n        }\n        // if we have an exception we know about we'll throw it directly without the wrapper exception\n        if (e.getCause() instanceof HystrixRuntimeException) {\n            return (HystrixRuntimeException) e.getCause();\n        }\n        if (shouldNotBeWrapped(e)) {\n            return e;\n        }\n        if (shouldNotBeWrapped(e.getCause())) {\n            return e.getCause();\n        }\n        // we don't know what kind of exception this is so create a generic message and throw a new HystrixRuntimeException\n        String message = getLogMessagePrefix() + \" failed while executing.\";\n        logger.debug(message, e); // debug only since we're throwing the exception and someone higher will do something with it\n        return new HystrixRuntimeException(FailureType.COMMAND_EXCEPTION, this.getClass(), message, e, null);\n\n    }\n\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n    /* TryableSemaphore */\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n\n    /**\n     * Semaphore that only supports tryAcquire and never blocks and that supports a dynamic permit count.\n     * <p>\n     * Using AtomicInteger increment/decrement instead of java.util.concurrent.Semaphore since we don't need blocking and need a custom implementation to get the dynamic permit count and since\n     * AtomicInteger achieves the same behavior and performance without the more complex implementation of the actual Semaphore class using AbstractQueueSynchronizer.\n     */\n    /* package */static class TryableSemaphoreActual implements TryableSemaphore {\n        protected final HystrixProperty<Integer> numberOfPermits;\n        private final AtomicInteger count = new AtomicInteger(0);\n\n        public TryableSemaphoreActual(HystrixProperty<Integer> numberOfPermits) {\n            this.numberOfPermits = numberOfPermits;\n        }\n\n        @Override\n        public boolean tryAcquire() {\n            int currentCount = count.incrementAndGet();\n            if (currentCount > numberOfPermits.get()) {\n                count.decrementAndGet();\n                return false;\n            } else {\n                return true;\n            }\n        }\n\n        @Override\n        public void release() {\n            count.decrementAndGet();\n        }\n\n        @Override\n        public int getNumberOfPermitsUsed() {\n            return count.get();\n        }\n\n    }\n\n    /* package */static class TryableSemaphoreNoOp implements TryableSemaphore {\n\n        public static final TryableSemaphore DEFAULT = new TryableSemaphoreNoOp();\n\n        @Override\n        public boolean tryAcquire() {\n            return true;\n        }\n\n        @Override\n        public void release() {\n\n        }\n\n        @Override\n        public int getNumberOfPermitsUsed() {\n            return 0;\n        }\n\n    }\n\n    /* package */static interface TryableSemaphore {\n\n        /**\n         * Use like this:\n         * <p>\n         * \n         * <pre>\n         * if (s.tryAcquire()) {\n         * try {\n         * // do work that is protected by 's'\n         * } finally {\n         * s.release();\n         * }\n         * }\n         * </pre>\n         * \n         * @return boolean\n         */\n        public abstract boolean tryAcquire();\n\n        /**\n         * ONLY call release if tryAcquire returned true.\n         * <p>\n         * \n         * <pre>\n         * if (s.tryAcquire()) {\n         * try {\n         * // do work that is protected by 's'\n         * } finally {\n         * s.release();\n         * }\n         * }\n         * </pre>\n         */\n        public abstract void release();\n\n        public abstract int getNumberOfPermitsUsed();\n\n    }\n\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n    /* RequestCache */\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n\n    /**\n     * Key to be used for request caching.\n     * <p>\n     * By default this returns null which means \"do not cache\".\n     * <p>\n     * To enable caching override this method and return a string key uniquely representing the state of a command instance.\n     * <p>\n     * If multiple command instances in the same request scope match keys then only the first will be executed and all others returned from cache.\n     * \n     * @return cacheKey\n     */\n    protected String getCacheKey() {\n        return null;\n    }\n\n    public String getPublicCacheKey() {\n        return getCacheKey();\n    }\n\n    protected boolean isRequestCachingEnabled() {\n        return properties.requestCacheEnabled().get() && getCacheKey() != null;\n    }\n\n    protected String getLogMessagePrefix() {\n        return getCommandKey().name();\n    }\n\n    /**\n     * Whether the 'circuit-breaker' is open meaning that <code>execute()</code> will immediately return\n     * the <code>getFallback()</code> response and not attempt a HystrixCommand execution.\n     *\n     * 4 columns are ForcedOpen | ForcedClosed | CircuitBreaker open due to health ||| Expected Result\n     *\n     * T | T | T ||| OPEN (true)\n     * T | T | F ||| OPEN (true)\n     * T | F | T ||| OPEN (true)\n     * T | F | F ||| OPEN (true)\n     * F | T | T ||| CLOSED (false)\n     * F | T | F ||| CLOSED (false)\n     * F | F | T ||| OPEN (true)\n     * F | F | F ||| CLOSED (false)\n     *\n     * @return boolean\n     */\n    public boolean isCircuitBreakerOpen() {\n        return properties.circuitBreakerForceOpen().get() || (!properties.circuitBreakerForceClosed().get() && circuitBreaker.isOpen());\n    }\n\n    /**\n     * If this command has completed execution either successfully, via fallback or failure.\n     * \n     * @return boolean\n     */\n    public boolean isExecutionComplete() {\n        return commandState.get() == CommandState.TERMINAL;\n    }\n\n    /**\n     * Whether the execution occurred in a separate thread.\n     * <p>\n     * This should be called only once execute()/queue()/fireOrForget() are called otherwise it will always return false.\n     * <p>\n     * This specifies if a thread execution actually occurred, not just if it is configured to be executed in a thread.\n     * \n     * @return boolean\n     */\n    public boolean isExecutedInThread() {\n        return getCommandResult().isExecutedInThread();\n    }\n\n    /**\n     * Whether the response was returned successfully either by executing <code>run()</code> or from cache.\n     * \n     * @return boolean\n     */\n    public boolean isSuccessfulExecution() {\n        return getCommandResult().getEventCounts().contains(HystrixEventType.SUCCESS);\n    }\n\n    /**\n     * Whether the <code>run()</code> resulted in a failure (exception).\n     * \n     * @return boolean\n     */\n    public boolean isFailedExecution() {\n        return getCommandResult().getEventCounts().contains(HystrixEventType.FAILURE);\n    }\n\n    /**\n     * Get the Throwable/Exception thrown that caused the failure.\n     * <p>\n     * If <code>isFailedExecution() == true</code> then this would represent the Exception thrown by the <code>run()</code> method.\n     * <p>\n     * If <code>isFailedExecution() == false</code> then this would return null.\n     * \n     * @return Throwable or null\n     */\n    public Throwable getFailedExecutionException() {\n        return executionResult.getException();\n    }\n\n    /**\n     * Get the Throwable/Exception emitted by this command instance prior to checking the fallback.\n     * This exception instance may have been generated via a number of mechanisms:\n     * 1) failed execution (in this case, same result as {@link #getFailedExecutionException()}.\n     * 2) timeout\n     * 3) short-circuit\n     * 4) rejection\n     * 5) bad request\n     *\n     * If the command execution was successful, then this exception instance is null (there was no exception)\n     *\n     * Note that the caller of the command may not receive this exception, as fallbacks may be served as a response to\n     * the exception.\n     *\n     * @return Throwable or null\n     */\n    public Throwable getExecutionException() {\n        return executionResult.getExecutionException();\n    }\n\n    /**\n     * Whether the response received from was the result of some type of failure\n     * and <code>getFallback()</code> being called.\n     * \n     * @return boolean\n     */\n    public boolean isResponseFromFallback() {\n        return getCommandResult().getEventCounts().contains(HystrixEventType.FALLBACK_SUCCESS);\n    }\n\n    /**\n     * Whether the response received was the result of a timeout\n     * and <code>getFallback()</code> being called.\n     * \n     * @return boolean\n     */\n    public boolean isResponseTimedOut() {\n        return getCommandResult().getEventCounts().contains(HystrixEventType.TIMEOUT);\n    }\n\n    /**\n     * Whether the response received was a fallback as result of being\n     * short-circuited (meaning <code>isCircuitBreakerOpen() == true</code>) and <code>getFallback()</code> being called.\n     * \n     * @return boolean\n     */\n    public boolean isResponseShortCircuited() {\n        return getCommandResult().getEventCounts().contains(HystrixEventType.SHORT_CIRCUITED);\n    }\n\n    /**\n     * Whether the response is from cache and <code>run()</code> was not invoked.\n     * \n     * @return boolean\n     */\n    public boolean isResponseFromCache() {\n        return isResponseFromCache;\n    }\n\n    /**\n     * Whether the response received was a fallback as result of being rejected via sempahore\n     *\n     * @return boolean\n     */\n    public boolean isResponseSemaphoreRejected() {\n        return getCommandResult().isResponseSemaphoreRejected();\n    }\n\n    /**\n     * Whether the response received was a fallback as result of being rejected via threadpool\n     *\n     * @return boolean\n     */\n    public boolean isResponseThreadPoolRejected() {\n        return getCommandResult().isResponseThreadPoolRejected();\n    }\n\n    /**\n     * Whether the response received was a fallback as result of being rejected (either via threadpool or semaphore)\n     *\n     * @return boolean\n     */\n    public boolean isResponseRejected() {\n        return getCommandResult().isResponseRejected();\n    }\n\n    /**\n     * List of HystrixCommandEventType enums representing events that occurred during execution.\n     * <p>\n     * Examples of events are SUCCESS, FAILURE, TIMEOUT, and SHORT_CIRCUITED\n     * \n     * @return {@code List<HystrixEventType>}\n     */\n    public List<HystrixEventType> getExecutionEvents() {\n        return getCommandResult().getOrderedList();\n    }\n\n    private ExecutionResult getCommandResult() {\n        ExecutionResult resultToReturn;\n        if (executionResultAtTimeOfCancellation == null) {\n            resultToReturn = executionResult;\n        } else {\n            resultToReturn = executionResultAtTimeOfCancellation;\n        }\n\n        if (isResponseFromCache) {\n            resultToReturn = resultToReturn.addEvent(HystrixEventType.RESPONSE_FROM_CACHE);\n        }\n\n        return resultToReturn;\n    }\n\n    /**\n     * Number of emissions of the execution of a command.  Only interesting in the streaming case.\n     * @return number of <code>OnNext</code> emissions by a streaming command\n     */\n    @Override\n    public int getNumberEmissions() {\n        return getCommandResult().getEventCounts().getCount(HystrixEventType.EMIT);\n    }\n\n    /**\n     * Number of emissions of the execution of a fallback.  Only interesting in the streaming case.\n     * @return number of <code>OnNext</code> emissions by a streaming fallback\n     */\n    @Override\n    public int getNumberFallbackEmissions() {\n        return getCommandResult().getEventCounts().getCount(HystrixEventType.FALLBACK_EMIT);\n    }\n\n    @Override\n    public int getNumberCollapsed() {\n        return getCommandResult().getEventCounts().getCount(HystrixEventType.COLLAPSED);\n    }\n\n    @Override\n    public HystrixCollapserKey getOriginatingCollapserKey() {\n        return executionResult.getCollapserKey();\n    }\n\n    /**\n     * The execution time of this command instance in milliseconds, or -1 if not executed.\n     * \n     * @return int\n     */\n    public int getExecutionTimeInMilliseconds() {\n        return getCommandResult().getExecutionLatency();\n    }\n\n    /**\n     * Time in Nanos when this command instance's run method was called, or -1 if not executed \n     * for e.g., command threw an exception\n      *\n      * @return long\n     */\n    public long getCommandRunStartTimeInNanos() {\n        return executionResult.getCommandRunStartTimeInNanos();\n    }\n\n    @Override\n    public ExecutionResult.EventCounts getEventCounts() {\n        return getCommandResult().getEventCounts();\n    }\n\n    protected Exception getExceptionFromThrowable(Throwable t) {\n        Exception e;\n        if (t instanceof Exception) {\n            e = (Exception) t;\n        } else {\n            // Hystrix 1.x uses Exception, not Throwable so to prevent a breaking change Throwable will be wrapped in Exception\n            e = new Exception(\"Throwable caught while executing.\", t);\n        }\n        return e;\n    }\n\n    private static class ExecutionHookDeprecationWrapper extends HystrixCommandExecutionHook {\n\n        private final HystrixCommandExecutionHook actual;\n\n        ExecutionHookDeprecationWrapper(HystrixCommandExecutionHook actual) {\n            this.actual = actual;\n        }\n\n        @Override\n        public <T> T onEmit(HystrixInvokable<T> commandInstance, T value) {\n            return actual.onEmit(commandInstance, value);\n        }\n\n        @Override\n        public <T> void onSuccess(HystrixInvokable<T> commandInstance) {\n            actual.onSuccess(commandInstance);\n        }\n\n        @Override\n        public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {\n            actual.onExecutionStart(commandInstance);\n        }\n\n        @Override\n        public <T> T onExecutionEmit(HystrixInvokable<T> commandInstance, T value) {\n            return actual.onExecutionEmit(commandInstance, value);\n        }\n\n        @Override\n        public <T> Exception onExecutionError(HystrixInvokable<T> commandInstance, Exception e) {\n            return actual.onExecutionError(commandInstance, e);\n        }\n\n        @Override\n        public <T> void onExecutionSuccess(HystrixInvokable<T> commandInstance) {\n            actual.onExecutionSuccess(commandInstance);\n        }\n\n        @Override\n        public <T> T onFallbackEmit(HystrixInvokable<T> commandInstance, T value) {\n            return actual.onFallbackEmit(commandInstance, value);\n        }\n\n        @Override\n        public <T> void onFallbackSuccess(HystrixInvokable<T> commandInstance) {\n            actual.onFallbackSuccess(commandInstance);\n        }\n\n        @Override\n        @Deprecated\n        public <T> void onRunStart(HystrixCommand<T> commandInstance) {\n            actual.onRunStart(commandInstance);\n        }\n\n        @Override\n        public <T> void onRunStart(HystrixInvokable<T> commandInstance) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                onRunStart(c);\n            }\n            actual.onRunStart(commandInstance);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onRunSuccess(HystrixCommand<T> commandInstance, T response) {\n            return actual.onRunSuccess(commandInstance, response);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onRunSuccess(HystrixInvokable<T> commandInstance, T response) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                response = onRunSuccess(c, response);\n            }\n            return actual.onRunSuccess(commandInstance, response);\n        }\n\n        @Override\n        @Deprecated\n        public <T> Exception onRunError(HystrixCommand<T> commandInstance, Exception e) {\n            return actual.onRunError(commandInstance, e);\n        }\n\n        @Override\n        @Deprecated\n        public <T> Exception onRunError(HystrixInvokable<T> commandInstance, Exception e) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                e = onRunError(c, e);\n            }\n            return actual.onRunError(commandInstance, e);\n        }\n\n        @Override\n        @Deprecated\n        public <T> void onFallbackStart(HystrixCommand<T> commandInstance) {\n            actual.onFallbackStart(commandInstance);\n        }\n\n        @Override\n        public <T> void onFallbackStart(HystrixInvokable<T> commandInstance) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                onFallbackStart(c);\n            }\n            actual.onFallbackStart(commandInstance);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onFallbackSuccess(HystrixCommand<T> commandInstance, T fallbackResponse) {\n            return actual.onFallbackSuccess(commandInstance, fallbackResponse);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onFallbackSuccess(HystrixInvokable<T> commandInstance, T fallbackResponse) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                fallbackResponse = onFallbackSuccess(c, fallbackResponse);\n            }\n            return actual.onFallbackSuccess(commandInstance, fallbackResponse);\n        }\n\n        @Override\n        @Deprecated\n        public <T> Exception onFallbackError(HystrixCommand<T> commandInstance, Exception e) {\n            return actual.onFallbackError(commandInstance, e);\n        }\n\n        @Override\n        public <T> Exception onFallbackError(HystrixInvokable<T> commandInstance, Exception e) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                e = onFallbackError(c, e);\n            }\n            return actual.onFallbackError(commandInstance, e);\n        }\n\n        @Override\n        @Deprecated\n        public <T> void onStart(HystrixCommand<T> commandInstance) {\n            actual.onStart(commandInstance);\n        }\n\n        @Override\n        public <T> void onStart(HystrixInvokable<T> commandInstance) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                onStart(c);\n            }\n            actual.onStart(commandInstance);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onComplete(HystrixCommand<T> commandInstance, T response) {\n            return actual.onComplete(commandInstance, response);\n        }\n\n        @Override\n        @Deprecated\n        public <T> T onComplete(HystrixInvokable<T> commandInstance, T response) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                response = onComplete(c, response);\n            }\n            return actual.onComplete(commandInstance, response);\n        }\n\n        @Override\n        @Deprecated\n        public <T> Exception onError(HystrixCommand<T> commandInstance, FailureType failureType, Exception e) {\n            return actual.onError(commandInstance, failureType, e);\n        }\n\n        @Override\n        public <T> Exception onError(HystrixInvokable<T> commandInstance, FailureType failureType, Exception e) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                e = onError(c, failureType, e);\n            }\n            return actual.onError(commandInstance, failureType, e);\n        }\n\n        @Override\n        @Deprecated\n        public <T> void onThreadStart(HystrixCommand<T> commandInstance) {\n            actual.onThreadStart(commandInstance);\n        }\n\n        @Override\n        public <T> void onThreadStart(HystrixInvokable<T> commandInstance) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                onThreadStart(c);\n            }\n            actual.onThreadStart(commandInstance);\n        }\n\n        @Override\n        @Deprecated\n        public <T> void onThreadComplete(HystrixCommand<T> commandInstance) {\n            actual.onThreadComplete(commandInstance);\n        }\n\n        @Override\n        public <T> void onThreadComplete(HystrixInvokable<T> commandInstance) {\n            HystrixCommand<T> c = getHystrixCommandFromAbstractIfApplicable(commandInstance);\n            if (c != null) {\n                onThreadComplete(c);\n            }\n            actual.onThreadComplete(commandInstance);\n        }\n\n        @Override\n        public <T> void onCacheHit(HystrixInvokable<T> commandInstance) {\n            actual.onCacheHit(commandInstance);\n        }\n\n        @Override\n        public <T> void onUnsubscribe(HystrixInvokable<T> commandInstance) {\n            actual.onUnsubscribe(commandInstance);\n        }\n\n        @SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n        private <T> HystrixCommand<T> getHystrixCommandFromAbstractIfApplicable(HystrixInvokable<T> commandInstance) {\n            if (commandInstance instanceof HystrixCommand) {\n                return (HystrixCommand) commandInstance;\n            } else {\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/ExecutionResult.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.ArrayList;\nimport java.util.BitSet;\nimport java.util.List;\n\n/**\n * Immutable holder class for the status of command execution.\n * <p>\n * This object can be referenced and \"modified\" by parent and child threads as well as by different instances of HystrixCommand since\n * 1 instance could create an ExecutionResult, cache a Future that refers to it, a 2nd instance execution then retrieves a Future\n * from cache and wants to append RESPONSE_FROM_CACHE to whatever the ExecutionResult was from the first command execution.\n * <p>\n * This being immutable forces and ensure thread-safety instead of using AtomicInteger/ConcurrentLinkedQueue and determining\n * when it's safe to mutate the object directly versus needing to deep-copy clone to a new instance.\n */\npublic class ExecutionResult {\n    private final EventCounts eventCounts;\n    private final Exception failedExecutionException;\n    private final Exception executionException;\n    private final long startTimestamp;\n    private final int executionLatency; //time spent in run() method\n    private final int userThreadLatency; //time elapsed between caller thread submitting request and response being visible to it\n    private final boolean executionOccurred;\n    private final boolean isExecutedInThread;\n    private final HystrixCollapserKey collapserKey;\n\n    private static final HystrixEventType[] ALL_EVENT_TYPES = HystrixEventType.values();\n    private static final int NUM_EVENT_TYPES = ALL_EVENT_TYPES.length;\n    private static final BitSet EXCEPTION_PRODUCING_EVENTS = new BitSet(NUM_EVENT_TYPES);\n    private static final BitSet TERMINAL_EVENTS = new BitSet(NUM_EVENT_TYPES);\n\n    static {\n        for (HystrixEventType eventType: HystrixEventType.EXCEPTION_PRODUCING_EVENT_TYPES) {\n            EXCEPTION_PRODUCING_EVENTS.set(eventType.ordinal());\n        }\n\n        for (HystrixEventType eventType: HystrixEventType.TERMINAL_EVENT_TYPES) {\n            TERMINAL_EVENTS.set(eventType.ordinal());\n        }\n    }\n\n    public static class EventCounts {\n        private final BitSet events;\n        private final int numEmissions;\n        private final int numFallbackEmissions;\n        private final int numCollapsed;\n\n        EventCounts() {\n            this.events = new BitSet(NUM_EVENT_TYPES);\n            this.numEmissions = 0;\n            this.numFallbackEmissions = 0;\n            this.numCollapsed = 0;\n        }\n\n        EventCounts(BitSet events, int numEmissions, int numFallbackEmissions, int numCollapsed) {\n            this.events = events;\n            this.numEmissions = numEmissions;\n            this.numFallbackEmissions = numFallbackEmissions;\n            this.numCollapsed = numCollapsed;\n        }\n\n        EventCounts(HystrixEventType... eventTypes) {\n            BitSet newBitSet = new BitSet(NUM_EVENT_TYPES);\n            int localNumEmits = 0;\n            int localNumFallbackEmits = 0;\n            int localNumCollapsed = 0;\n            for (HystrixEventType eventType: eventTypes) {\n                switch (eventType) {\n                    case EMIT:\n                        newBitSet.set(HystrixEventType.EMIT.ordinal());\n                        localNumEmits++;\n                        break;\n                    case FALLBACK_EMIT:\n                        newBitSet.set(HystrixEventType.FALLBACK_EMIT.ordinal());\n                        localNumFallbackEmits++;\n                        break;\n                    case COLLAPSED:\n                        newBitSet.set(HystrixEventType.COLLAPSED.ordinal());\n                        localNumCollapsed++;\n                        break;\n                    default:\n                        newBitSet.set(eventType.ordinal());\n                        break;\n                }\n            }\n            this.events = newBitSet;\n            this.numEmissions = localNumEmits;\n            this.numFallbackEmissions = localNumFallbackEmits;\n            this.numCollapsed = localNumCollapsed;\n        }\n\n        EventCounts plus(HystrixEventType eventType) {\n            return plus(eventType, 1);\n        }\n\n        EventCounts plus(HystrixEventType eventType, int count) {\n            BitSet newBitSet = (BitSet) events.clone();\n            int localNumEmits = numEmissions;\n            int localNumFallbackEmits =  numFallbackEmissions;\n            int localNumCollapsed = numCollapsed;\n            switch (eventType) {\n                case EMIT:\n                    newBitSet.set(HystrixEventType.EMIT.ordinal());\n                    localNumEmits += count;\n                    break;\n                case FALLBACK_EMIT:\n                    newBitSet.set(HystrixEventType.FALLBACK_EMIT.ordinal());\n                    localNumFallbackEmits += count;\n                    break;\n                case COLLAPSED:\n                    newBitSet.set(HystrixEventType.COLLAPSED.ordinal());\n                    localNumCollapsed += count;\n                    break;\n                default:\n                    newBitSet.set(eventType.ordinal());\n                    break;\n            }\n            return new EventCounts(newBitSet, localNumEmits, localNumFallbackEmits, localNumCollapsed);\n        }\n\n        public boolean contains(HystrixEventType eventType) {\n            return events.get(eventType.ordinal());\n        }\n\n        public boolean containsAnyOf(BitSet other) {\n            return events.intersects(other);\n        }\n\n        public int getCount(HystrixEventType eventType) {\n            switch (eventType) {\n                case EMIT: return numEmissions;\n                case FALLBACK_EMIT: return numFallbackEmissions;\n                case EXCEPTION_THROWN: return containsAnyOf(EXCEPTION_PRODUCING_EVENTS) ? 1 : 0;\n                case COLLAPSED: return numCollapsed;\n                default: return contains(eventType) ? 1 : 0;\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            EventCounts that = (EventCounts) o;\n\n            if (numEmissions != that.numEmissions) return false;\n            if (numFallbackEmissions != that.numFallbackEmissions) return false;\n            if (numCollapsed != that.numCollapsed) return false;\n            return events.equals(that.events);\n\n        }\n\n        @Override\n        public int hashCode() {\n            int result = events.hashCode();\n            result = 31 * result + numEmissions;\n            result = 31 * result + numFallbackEmissions;\n            result = 31 * result + numCollapsed;\n            return result;\n        }\n\n        @Override\n        public String toString() {\n            return \"EventCounts{\" +\n                    \"events=\" + events +\n                    \", numEmissions=\" + numEmissions +\n                    \", numFallbackEmissions=\" + numFallbackEmissions +\n                    \", numCollapsed=\" + numCollapsed +\n                    '}';\n        }\n    }\n\n    private ExecutionResult(EventCounts eventCounts, long startTimestamp, int executionLatency,\n                            int userThreadLatency, Exception failedExecutionException, Exception executionException,\n                            boolean executionOccurred, boolean isExecutedInThread, HystrixCollapserKey collapserKey) {\n        this.eventCounts = eventCounts;\n        this.startTimestamp = startTimestamp;\n        this.executionLatency = executionLatency;\n        this.userThreadLatency = userThreadLatency;\n        this.failedExecutionException = failedExecutionException;\n        this.executionException = executionException;\n        this.executionOccurred = executionOccurred;\n        this.isExecutedInThread = isExecutedInThread;\n        this.collapserKey = collapserKey;\n    }\n\n    // we can return a static version since it's immutable\n    static ExecutionResult EMPTY = ExecutionResult.from();\n\n    public static ExecutionResult from(HystrixEventType... eventTypes) {\n        boolean didExecutionOccur = false;\n        for (HystrixEventType eventType: eventTypes) {\n            if (didExecutionOccur(eventType)) {\n                didExecutionOccur = true;\n            }\n        }\n        return new ExecutionResult(new EventCounts(eventTypes), -1L, -1, -1, null, null, didExecutionOccur, false, null);\n    }\n\n    private static boolean didExecutionOccur(HystrixEventType eventType) {\n        switch (eventType) {\n            case SUCCESS: return true;\n            case FAILURE: return true;\n            case BAD_REQUEST: return true;\n            case TIMEOUT: return true;\n            case CANCELLED: return true;\n            default: return false;\n        }\n    }\n\n    public ExecutionResult setExecutionOccurred() {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, true, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult setExecutionLatency(int executionLatency) {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult setException(Exception e) {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency, e,\n                executionException, executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult setExecutionException(Exception executionException) {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult setInvocationStartTime(long startTimestamp) {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult setExecutedInThread() {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, true, collapserKey);\n    }\n\n    public ExecutionResult setNotExecutedInThread() {\n        return new ExecutionResult(eventCounts, startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, false, collapserKey);\n    }\n\n    public ExecutionResult markCollapsed(HystrixCollapserKey collapserKey, int sizeOfBatch) {\n        return new ExecutionResult(eventCounts.plus(HystrixEventType.COLLAPSED, sizeOfBatch), startTimestamp, executionLatency, userThreadLatency,\n                failedExecutionException, executionException, executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult markUserThreadCompletion(long userThreadLatency) {\n        if (startTimestamp > 0 && !isResponseRejected()) {\n            /* execution time (must occur before terminal state otherwise a race condition can occur if requested by client) */\n            return new ExecutionResult(eventCounts, startTimestamp, executionLatency, (int) userThreadLatency,\n                    failedExecutionException, executionException, executionOccurred, isExecutedInThread, collapserKey);\n        } else {\n            return this;\n        }\n    }\n\n    /**\n     * Creates a new ExecutionResult by adding the defined 'event' to the ones on the current instance.\n     *\n     * @param eventType event to add\n     * @return new {@link ExecutionResult} with event added\n     */\n    public ExecutionResult addEvent(HystrixEventType eventType) {\n        return new ExecutionResult(eventCounts.plus(eventType), startTimestamp, executionLatency,\n                userThreadLatency, failedExecutionException, executionException,\n                executionOccurred, isExecutedInThread, collapserKey);\n    }\n\n    public ExecutionResult addEvent(int executionLatency, HystrixEventType eventType) {\n        if (startTimestamp >= 0 && !isResponseRejected()) {\n            return new ExecutionResult(eventCounts.plus(eventType), startTimestamp, executionLatency,\n                    userThreadLatency, failedExecutionException, executionException,\n                    executionOccurred, isExecutedInThread, collapserKey);\n        } else {\n            return addEvent(eventType);\n        }\n    }\n\n    public EventCounts getEventCounts() {\n        return eventCounts;\n    }\n\n    public long getStartTimestamp() {\n        return startTimestamp;\n    }\n\n    public int getExecutionLatency() {\n        return executionLatency;\n    }\n\n    public int getUserThreadLatency() {\n        return userThreadLatency;\n    }\n\n    public long getCommandRunStartTimeInNanos() {\n        return startTimestamp * 1000 * 1000;\n    }\n\n    public Exception getException() {\n        return failedExecutionException;\n    }\n\n    public Exception getExecutionException() {\n        return executionException;\n    }\n\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserKey;\n    }\n\n    public boolean isResponseSemaphoreRejected() {\n        return eventCounts.contains(HystrixEventType.SEMAPHORE_REJECTED);\n    }\n\n    public boolean isResponseThreadPoolRejected() {\n        return eventCounts.contains(HystrixEventType.THREAD_POOL_REJECTED);\n    }\n\n    public boolean isResponseRejected() {\n        return isResponseThreadPoolRejected() || isResponseSemaphoreRejected();\n    }\n\n    public List<HystrixEventType> getOrderedList() {\n        List<HystrixEventType> eventList = new ArrayList<HystrixEventType>();\n        for (HystrixEventType eventType: ALL_EVENT_TYPES) {\n            if (eventCounts.contains(eventType)) {\n                eventList.add(eventType);\n            }\n        }\n        return eventList;\n    }\n\n    public boolean isExecutedInThread() {\n        return isExecutedInThread;\n    }\n\n    public boolean executionOccurred() {\n        return executionOccurred;\n    }\n\n    public boolean containsTerminalEvent() {\n        return eventCounts.containsAnyOf(TERMINAL_EVENTS);\n    }\n\n    @Override\n    public String toString() {\n        return \"ExecutionResult{\" +\n                \"eventCounts=\" + eventCounts +\n                \", failedExecutionException=\" + failedExecutionException +\n                \", executionException=\" + executionException +\n                \", startTimestamp=\" + startTimestamp +\n                \", executionLatency=\" + executionLatency +\n                \", userThreadLatency=\" + userThreadLatency +\n                \", executionOccurred=\" + executionOccurred +\n                \", isExecutedInThread=\" + isExecutedInThread +\n                \", collapserKey=\" + collapserKey +\n                '}';\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/Hystrix.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport rx.functions.Action0;\n\n/**\n * Lifecycle management of Hystrix.\n */\npublic class Hystrix {\n\n    private static final Logger logger = LoggerFactory.getLogger(Hystrix.class);\n\n    /**\n     * Reset state and release resources in use (such as thread-pools).\n     * <p>\n     * NOTE: This can result in race conditions if HystrixCommands are concurrently being executed.\n     * </p>\n     */\n    public static void reset() {\n        // shutdown thread-pools\n        HystrixThreadPool.Factory.shutdown();\n        _reset();\n    }\n\n    /**\n     * Reset state and release resources in use (such as threadpools) and wait for completion.\n     * <p>\n     * NOTE: This can result in race conditions if HystrixCommands are concurrently being executed.\n     * </p>\n     * \n     * @param time\n     *            time to wait for thread-pools to shutdown\n     * @param unit\n     *            {@link TimeUnit} for <pre>time</pre> to wait for thread-pools to shutdown\n     */\n    public static void reset(long time, TimeUnit unit) {\n        // shutdown thread-pools\n        HystrixThreadPool.Factory.shutdown(time, unit);\n        _reset();\n    }\n\n    /**\n     * Reset logic that doesn't have time/TimeUnit arguments.\n     */\n    private static void _reset() {\n        // clear metrics\n        HystrixCommandMetrics.reset();\n        HystrixThreadPoolMetrics.reset();\n        HystrixCollapserMetrics.reset();\n        // clear collapsers\n        HystrixCollapser.reset();\n        // clear circuit breakers\n        HystrixCircuitBreaker.Factory.reset();\n        HystrixPlugins.reset();\n        HystrixPropertiesFactory.reset();\n        currentCommand.set(new ConcurrentStack<HystrixCommandKey>());\n    }\n\n    private static ThreadLocal<ConcurrentStack<HystrixCommandKey>> currentCommand = new ThreadLocal<ConcurrentStack<HystrixCommandKey>>() {\n        @Override\n        protected ConcurrentStack<HystrixCommandKey> initialValue() {\n            return new ConcurrentStack<HystrixCommandKey>();\n        }\n    };\n\n    /**\n     * Allows a thread to query whether it's current point of execution is within the scope of a HystrixCommand.\n     * <p>\n     * When ExecutionIsolationStrategy is THREAD then this applies to the isolation (child/worker) thread not the calling thread.\n     * <p>\n     * When ExecutionIsolationStrategy is SEMAPHORE this applies to the calling thread.\n     * \n     * @return HystrixCommandKey of current command being executed or null if none.\n     */\n    public static HystrixCommandKey getCurrentThreadExecutingCommand() {\n        if (currentCommand == null) {\n            // statics do \"interesting\" things across classloaders apparently so this can somehow be null ... \n            return null;\n        }\n        return currentCommand.get().peek();\n    }\n\n    /**\n     * \n     * @return Action0 to perform the same work as `endCurrentThreadExecutingCommand()` but can be done from any thread\n     */\n    /* package */static Action0 startCurrentThreadExecutingCommand(HystrixCommandKey key) {\n        final ConcurrentStack<HystrixCommandKey> list = currentCommand.get();\n        try {\n            list.push(key);\n        } catch (Exception e) {\n            logger.warn(\"Unable to record command starting\", e);\n        }\n        return new Action0() {\n\n            @Override\n            public void call() {\n                endCurrentThreadExecutingCommand(list);\n            }\n\n        };\n    }\n\n    /* package */static void endCurrentThreadExecutingCommand() {\n        endCurrentThreadExecutingCommand(currentCommand.get());\n    }\n\n    private static void endCurrentThreadExecutingCommand(ConcurrentStack<HystrixCommandKey> list) {\n        try {\n            if (!list.isEmpty()) {\n                list.pop();\n            }\n        } catch (NoSuchElementException e) {\n            // this shouldn't be possible since we check for empty above and this is thread-isolated\n            logger.debug(\"No command found to end.\", e);\n        } catch (Exception e) {\n            logger.warn(\"Unable to end command.\", e);\n        }\n    }\n\n    /* package-private */ static int getCommandCount() {\n        return currentCommand.get().size();\n    }\n\n    /**\n     * Trieber's algorithm for a concurrent stack\n     * @param <E>\n     */\n    private static class ConcurrentStack<E> {\n        AtomicReference<Node<E>> top = new AtomicReference<Node<E>>();\n\n        public void push(E item) {\n            Node<E> newHead = new Node<E>(item);\n            Node<E> oldHead;\n            do {\n                oldHead = top.get();\n                newHead.next = oldHead;\n            } while (!top.compareAndSet(oldHead, newHead));\n        }\n\n        public E pop() {\n            Node<E> oldHead;\n            Node<E> newHead;\n            do {\n                oldHead = top.get();\n                if (oldHead == null) {\n                    return null;\n                }\n                newHead = oldHead.next;\n            } while (!top.compareAndSet(oldHead, newHead));\n            return oldHead.item;\n        }\n\n        public boolean isEmpty() {\n            return top.get() == null;\n        }\n\n        public int size() {\n            int currentSize = 0;\n            Node<E> current = top.get();\n            while (current != null) {\n                currentSize++;\n                current = current.next;\n            }\n            return currentSize;\n        }\n\n        public E peek() {\n            Node<E> eNode = top.get();\n            if (eNode == null) {\n                return null;\n            } else {\n                return eNode.item;\n            }\n        }\n\n        private class Node<E> {\n            public final E item;\n            public Node<E> next;\n\n            public Node(E item) {\n                this.item = item;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCachedObservable.java",
    "content": "package com.netflix.hystrix;\n\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.subjects.ReplaySubject;\n\npublic class HystrixCachedObservable<R> {\n    protected final Subscription originalSubscription;\n    protected final Observable<R> cachedObservable;\n    private volatile int outstandingSubscriptions = 0;\n\n    protected HystrixCachedObservable(final Observable<R> originalObservable) {\n        ReplaySubject<R> replaySubject = ReplaySubject.create();\n        this.originalSubscription = originalObservable\n                .subscribe(replaySubject);\n\n        this.cachedObservable = replaySubject\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        outstandingSubscriptions--;\n                        if (outstandingSubscriptions == 0) {\n                            originalSubscription.unsubscribe();\n                        }\n                    }\n                })\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        outstandingSubscriptions++;\n                    }\n                });\n    }\n\n    public static <R> HystrixCachedObservable<R> from(Observable<R> o, AbstractCommand<R> originalCommand) {\n        return new HystrixCommandResponseFromCache<R>(o, originalCommand);\n    }\n\n    public static <R> HystrixCachedObservable<R> from(Observable<R> o) {\n        return new HystrixCachedObservable<R>(o);\n    }\n\n    public Observable<R> toObservable() {\n        return cachedObservable;\n    }\n\n    public void unsubscribe() {\n        originalSubscription.unsubscribe();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCircuitBreaker.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;\nimport rx.Subscriber;\nimport rx.Subscription;\n\n/**\n * Circuit-breaker logic that is hooked into {@link HystrixCommand} execution and will stop allowing executions if failures have gone past the defined threshold.\n * <p>\n * The default (and only) implementation  will then allow a single retry after a defined sleepWindow until the execution\n * succeeds at which point it will again close the circuit and allow executions again.\n */\npublic interface HystrixCircuitBreaker {\n\n    /**\n     * Every {@link HystrixCommand} requests asks this if it is allowed to proceed or not.  It is idempotent and does\n     * not modify any internal state, and takes into account the half-open logic which allows some requests through\n     * after the circuit has been opened\n     * \n     * @return boolean whether a request should be permitted\n     */\n    boolean allowRequest();\n\n    /**\n     * Whether the circuit is currently open (tripped).\n     * \n     * @return boolean state of circuit breaker\n     */\n    boolean isOpen();\n\n    /**\n     * Invoked on successful executions from {@link HystrixCommand} as part of feedback mechanism when in a half-open state.\n     */\n    void markSuccess();\n\n    /**\n     * Invoked on unsuccessful executions from {@link HystrixCommand} as part of feedback mechanism when in a half-open state.\n     */\n    void markNonSuccess();\n\n    /**\n     * Invoked at start of command execution to attempt an execution.  This is non-idempotent - it may modify internal\n     * state.\n     */\n    boolean attemptExecution();\n\n    /**\n     * @ExcludeFromJavadoc\n     * @ThreadSafe\n     */\n    class Factory {\n        // String is HystrixCommandKey.name() (we can't use HystrixCommandKey directly as we can't guarantee it implements hashcode/equals correctly)\n        private static ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand = new ConcurrentHashMap<String, HystrixCircuitBreaker>();\n\n        /**\n         * Get the {@link HystrixCircuitBreaker} instance for a given {@link HystrixCommandKey}.\n         * <p>\n         * This is thread-safe and ensures only 1 {@link HystrixCircuitBreaker} per {@link HystrixCommandKey}.\n         * \n         * @param key\n         *            {@link HystrixCommandKey} of {@link HystrixCommand} instance requesting the {@link HystrixCircuitBreaker}\n         * @param group\n         *            Pass-thru to {@link HystrixCircuitBreaker}\n         * @param properties\n         *            Pass-thru to {@link HystrixCircuitBreaker}\n         * @param metrics\n         *            Pass-thru to {@link HystrixCircuitBreaker}\n         * @return {@link HystrixCircuitBreaker} for {@link HystrixCommandKey}\n         */\n        public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {\n            // this should find it for all but the first time\n            HystrixCircuitBreaker previouslyCached = circuitBreakersByCommand.get(key.name());\n            if (previouslyCached != null) {\n                return previouslyCached;\n            }\n\n            // if we get here this is the first time so we need to initialize\n\n            // Create and add to the map ... use putIfAbsent to atomically handle the possible race-condition of\n            // 2 threads hitting this point at the same time and let ConcurrentHashMap provide us our thread-safety\n            // If 2 threads hit here only one will get added and the other will get a non-null response instead.\n            HystrixCircuitBreaker cbForCommand = circuitBreakersByCommand.putIfAbsent(key.name(), new HystrixCircuitBreakerImpl(key, group, properties, metrics));\n            if (cbForCommand == null) {\n                // this means the putIfAbsent step just created a new one so let's retrieve and return it\n                return circuitBreakersByCommand.get(key.name());\n            } else {\n                // this means a race occurred and while attempting to 'put' another one got there before\n                // and we instead retrieved it and will now return it\n                return cbForCommand;\n            }\n        }\n\n        /**\n         * Get the {@link HystrixCircuitBreaker} instance for a given {@link HystrixCommandKey} or null if none exists.\n         * \n         * @param key\n         *            {@link HystrixCommandKey} of {@link HystrixCommand} instance requesting the {@link HystrixCircuitBreaker}\n         * @return {@link HystrixCircuitBreaker} for {@link HystrixCommandKey}\n         */\n        public static HystrixCircuitBreaker getInstance(HystrixCommandKey key) {\n            return circuitBreakersByCommand.get(key.name());\n        }\n\n        /**\n         * Clears all circuit breakers. If new requests come in instances will be recreated.\n         */\n        /* package */static void reset() {\n            circuitBreakersByCommand.clear();\n        }\n    }\n\n\n    /**\n     * The default production implementation of {@link HystrixCircuitBreaker}.\n     * \n     * @ExcludeFromJavadoc\n     * @ThreadSafe\n     */\n    /* package */class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {\n        private final HystrixCommandProperties properties;\n        private final HystrixCommandMetrics metrics;\n\n        enum Status {\n            CLOSED, OPEN, HALF_OPEN;\n        }\n\n        private final AtomicReference<Status> status = new AtomicReference<Status>(Status.CLOSED);\n        private final AtomicLong circuitOpened = new AtomicLong(-1);\n        private final AtomicReference<Subscription> activeSubscription = new AtomicReference<Subscription>(null);\n\n        protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, final HystrixCommandProperties properties, HystrixCommandMetrics metrics) {\n            this.properties = properties;\n            this.metrics = metrics;\n\n            //On a timer, this will set the circuit between OPEN/CLOSED as command executions occur\n            Subscription s = subscribeToStream();\n            activeSubscription.set(s);\n        }\n\n        private Subscription subscribeToStream() {\n            /*\n             * This stream will recalculate the OPEN/CLOSED status on every onNext from the health stream\n             */\n            return metrics.getHealthCountsStream()\n                    .observe()\n                    .subscribe(new Subscriber<HealthCounts>() {\n                        @Override\n                        public void onCompleted() {\n\n                        }\n\n                        @Override\n                        public void onError(Throwable e) {\n\n                        }\n\n                        @Override\n                        public void onNext(HealthCounts hc) {\n                            // check if we are past the statisticalWindowVolumeThreshold\n                            if (hc.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {\n                                // we are not past the minimum volume threshold for the stat window,\n                                // so no change to circuit status.\n                                // if it was CLOSED, it stays CLOSED\n                                // if it was half-open, we need to wait for a successful command execution\n                                // if it was open, we need to wait for sleep window to elapse\n                            } else {\n                                if (hc.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {\n                                    //we are not past the minimum error threshold for the stat window,\n                                    // so no change to circuit status.\n                                    // if it was CLOSED, it stays CLOSED\n                                    // if it was half-open, we need to wait for a successful command execution\n                                    // if it was open, we need to wait for sleep window to elapse\n                                } else {\n                                    // our failure rate is too high, we need to set the state to OPEN\n                                    if (status.compareAndSet(Status.CLOSED, Status.OPEN)) {\n                                        circuitOpened.set(System.currentTimeMillis());\n                                    }\n                                }\n                            }\n                        }\n                    });\n        }\n\n        @Override\n        public void markSuccess() {\n            if (status.compareAndSet(Status.HALF_OPEN, Status.CLOSED)) {\n                //This thread wins the race to close the circuit - it resets the stream to start it over from 0\n                metrics.resetStream();\n                Subscription previousSubscription = activeSubscription.get();\n                if (previousSubscription != null) {\n                    previousSubscription.unsubscribe();\n                }\n                Subscription newSubscription = subscribeToStream();\n                activeSubscription.set(newSubscription);\n                circuitOpened.set(-1L);\n            }\n        }\n\n        @Override\n        public void markNonSuccess() {\n            if (status.compareAndSet(Status.HALF_OPEN, Status.OPEN)) {\n                //This thread wins the race to re-open the circuit - it resets the start time for the sleep window\n                circuitOpened.set(System.currentTimeMillis());\n            }\n        }\n\n        @Override\n        public boolean isOpen() {\n            if (properties.circuitBreakerForceOpen().get()) {\n                return true;\n            }\n            if (properties.circuitBreakerForceClosed().get()) {\n                return false;\n            }\n            return circuitOpened.get() >= 0;\n        }\n\n        @Override\n        public boolean allowRequest() {\n            if (properties.circuitBreakerForceOpen().get()) {\n                return false;\n            }\n            if (properties.circuitBreakerForceClosed().get()) {\n                return true;\n            }\n            if (circuitOpened.get() == -1) {\n                return true;\n            } else {\n                if (status.get().equals(Status.HALF_OPEN)) {\n                    return false;\n                } else {\n                    return isAfterSleepWindow();\n                }\n            }\n        }\n\n        private boolean isAfterSleepWindow() {\n            final long circuitOpenTime = circuitOpened.get();\n            final long currentTime = System.currentTimeMillis();\n            final long sleepWindowTime = properties.circuitBreakerSleepWindowInMilliseconds().get();\n            return currentTime > circuitOpenTime + sleepWindowTime;\n        }\n\n        @Override\n        public boolean attemptExecution() {\n            if (properties.circuitBreakerForceOpen().get()) {\n                return false;\n            }\n            if (properties.circuitBreakerForceClosed().get()) {\n                return true;\n            }\n            if (circuitOpened.get() == -1) {\n                return true;\n            } else {\n                if (isAfterSleepWindow()) {\n                    //only the first request after sleep window should execute\n                    //if the executing command succeeds, the status will transition to CLOSED\n                    //if the executing command fails, the status will transition to OPEN\n                    //if the executing command gets unsubscribed, the status will transition to OPEN\n                    if (status.compareAndSet(Status.OPEN, Status.HALF_OPEN)) {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                } else {\n                    return false;\n                }\n            }\n        }\n    }\n\n    /**\n     * An implementation of the circuit breaker that does nothing.\n     * \n     * @ExcludeFromJavadoc\n     */\n    /* package */static class NoOpCircuitBreaker implements HystrixCircuitBreaker {\n\n        @Override\n        public boolean allowRequest() {\n            return true;\n        }\n\n        @Override\n        public boolean isOpen() {\n            return false;\n        }\n\n        @Override\n        public void markSuccess() {\n\n        }\n\n        @Override\n        public void markNonSuccess() {\n\n        }\n\n        @Override\n        public boolean attemptExecution() {\n            return true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapser.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.collapser.CollapserTimer;\nimport com.netflix.hystrix.collapser.HystrixCollapserBridge;\nimport com.netflix.hystrix.collapser.RealCollapserTimer;\nimport com.netflix.hystrix.collapser.RequestCollapser;\nimport com.netflix.hystrix.collapser.RequestCollapserFactory;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\nimport rx.schedulers.Schedulers;\nimport rx.subjects.ReplaySubject;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Future;\n\n/**\n * Collapse multiple requests into a single {@link HystrixCommand} execution based on a time window and optionally a max batch size.\n * <p>\n * This allows an object model to have multiple calls to the command that execute/queue many times in a short period (milliseconds) and have them all get batched into a single backend call.\n * <p>\n * Typically the time window is something like 10ms give or take.\n * <p>\n * NOTE: Do NOT retain any state within instances of this class.\n * <p>\n * It must be stateless or else it will be non-deterministic because most instances are discarded while some are retained and become the\n * \"collapsers\" for all the ones that are discarded.\n * \n * @param <BatchReturnType>\n *            The type returned from the {@link HystrixCommand} that will be invoked on batch executions.\n * @param <ResponseType>\n *            The type returned from this command.\n * @param <RequestArgumentType>\n *            The type of the request argument. If multiple arguments are needed, wrap them in another object or a Tuple.\n */\npublic abstract class HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType> implements HystrixExecutable<ResponseType>, HystrixObservable<ResponseType> {\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixCollapser.class);\n\n    private final RequestCollapserFactory<BatchReturnType, ResponseType, RequestArgumentType> collapserFactory;\n    private final HystrixRequestCache requestCache;\n    private final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> collapserInstanceWrapper;\n    private final HystrixCollapserMetrics metrics;\n\n    /**\n     * The scope of request collapsing.\n     * <ul>\n     * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed.\n     * <p>\n     * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request.\n     * </li>\n     * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li>\n     * </ul>\n     */\n    public static enum Scope implements RequestCollapserFactory.Scope {\n        REQUEST, GLOBAL\n    }\n\n    /**\n     * Collapser with default {@link HystrixCollapserKey} derived from the implementing class name and scoped to {@link Scope#REQUEST} and default configuration.\n     */\n    protected HystrixCollapser() {\n        this(Setter.withCollapserKey(null).andScope(Scope.REQUEST));\n    }\n\n    /**\n     * Collapser scoped to {@link Scope#REQUEST} and default configuration.\n     * \n     * @param collapserKey\n     *            {@link HystrixCollapserKey} that identifies this collapser and provides the key used for retrieving properties, request caches, publishing metrics etc.\n     */\n    protected HystrixCollapser(HystrixCollapserKey collapserKey) {\n        this(Setter.withCollapserKey(collapserKey).andScope(Scope.REQUEST));\n    }\n\n    /**\n     * Construct a {@link HystrixCollapser} with defined {@link Setter} that allows\n     * injecting property and strategy overrides and other optional arguments.\n     * <p>\n     * Null values will result in the default being used.\n     * \n     * @param setter\n     *            Fluent interface for constructor arguments\n     */\n    protected HystrixCollapser(Setter setter) {\n        this(setter.collapserKey, setter.scope, new RealCollapserTimer(), setter.propertiesSetter, null);\n    }\n\n    /* package for tests */ HystrixCollapser(HystrixCollapserKey collapserKey, Scope scope, CollapserTimer timer, HystrixCollapserProperties.Setter propertiesBuilder) {\n        this(collapserKey, scope, timer, propertiesBuilder, null);\n    }\n\n    /* package for tests */ HystrixCollapser(HystrixCollapserKey collapserKey, Scope scope, CollapserTimer timer, HystrixCollapserProperties.Setter propertiesBuilder, HystrixCollapserMetrics metrics) {\n        if (collapserKey == null || collapserKey.name().trim().equals(\"\")) {\n            String defaultKeyName = getDefaultNameFromClass(getClass());\n            collapserKey = HystrixCollapserKey.Factory.asKey(defaultKeyName);\n        }\n\n        HystrixCollapserProperties properties = HystrixPropertiesFactory.getCollapserProperties(collapserKey, propertiesBuilder);\n        this.collapserFactory = new RequestCollapserFactory<BatchReturnType, ResponseType, RequestArgumentType>(collapserKey, scope, timer, properties);\n        this.requestCache = HystrixRequestCache.getInstance(collapserKey, HystrixPlugins.getInstance().getConcurrencyStrategy());\n\n        if (metrics == null) {\n            this.metrics = HystrixCollapserMetrics.getInstance(collapserKey, properties);\n        } else {\n            this.metrics = metrics;\n        }\n\n        final HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType> self = this;\n\n         /* strategy: HystrixMetricsPublisherCollapser */\n        HystrixMetricsPublisherFactory.createOrRetrievePublisherForCollapser(collapserKey, this.metrics, properties);\n\n        /**\n         * Used to pass public method invocation to the underlying implementation in a separate package while leaving the methods 'protected' in this class.\n         */\n        collapserInstanceWrapper = new HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType>() {\n\n            @Override\n            public Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shardRequests(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shards = self.shardRequests(requests);\n                self.metrics.markShards(shards.size());\n                return shards;\n            }\n\n            @Override\n            public Observable<BatchReturnType> createObservableCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                final HystrixCommand<BatchReturnType> command = self.createCommand(requests);\n\n                command.markAsCollapsedCommand(this.getCollapserKey(), requests.size());\n                self.metrics.markBatch(requests.size());\n\n                return command.toObservable();\n            }\n\n            @Override\n            public Observable<Void> mapResponseToRequests(Observable<BatchReturnType> batchResponse, final Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                return batchResponse.single().doOnNext(new Action1<BatchReturnType>() {\n                    @Override\n                    public void call(BatchReturnType batchReturnType) {\n                        // this is a blocking call in HystrixCollapser\n                        self.mapResponseToRequests(batchReturnType, requests);\n                    }\n                }).ignoreElements().cast(Void.class);\n            }\n\n            @Override\n            public HystrixCollapserKey getCollapserKey() {\n                return self.getCollapserKey();\n            }\n\n        };\n    }\n\n    private HystrixCollapserProperties getProperties() {\n        return collapserFactory.getProperties();\n    }\n\n    /**\n     * Key of the {@link HystrixCollapser} used for properties, metrics, caches, reporting etc.\n     * \n     * @return {@link HystrixCollapserKey} identifying this {@link HystrixCollapser} instance\n     */\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserFactory.getCollapserKey();\n    }\n\n    /**\n     * Scope of collapsing.\n     * <p>\n     * <ul>\n     * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed.\n     * <p>\n     * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request.\n     * </li>\n     * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li>\n     * </ul>\n     * <p>\n     * Default: {@link Scope#REQUEST} (defined via constructor)\n     * \n     * @return {@link Scope} that collapsing should be performed within.\n     */\n    public Scope getScope() {\n        return Scope.valueOf(collapserFactory.getScope().name());\n    }\n\n    /**\n     * Return the {@link HystrixCollapserMetrics} for this collapser\n     * @return {@link HystrixCollapserMetrics} for this collapser\n     */\n    public HystrixCollapserMetrics getMetrics() {\n        return metrics;\n    }\n\n    /**\n     * The request arguments to be passed to the {@link HystrixCommand}.\n     * <p>\n     * Typically this means to take the argument(s) provided to the constructor and return it here.\n     * <p>\n     * If there are multiple arguments that need to be bundled, create a single object to contain them, or use a Tuple.\n     * \n     * @return RequestArgumentType\n     */\n    public abstract RequestArgumentType getRequestArgument();\n\n    /**\n     * Factory method to create a new {@link HystrixCommand}{@code <BatchReturnType>} command object each time a batch needs to be executed.\n     * <p>\n     * Do not return the same instance each time. Return a new instance on each invocation.\n     * <p>\n     * Process the 'requests' argument into the arguments the command object needs to perform its work.\n     * <p>\n     * If a batch or requests needs to be split (sharded) into multiple commands, see {@link #shardRequests} <p>\n     * IMPLEMENTATION NOTE: Be fast (ie. <1ms) in this method otherwise it can block the Timer from executing subsequent batches. Do not do any processing beyond constructing the command and returning\n     * it.\n     * \n     * @param requests\n     *            {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} containing {@link CollapsedRequest} objects containing the arguments of each request collapsed in this batch.\n     * @return {@link HystrixCommand}{@code <BatchReturnType>} which when executed will retrieve results for the batch of arguments as found in the Collection of {@link CollapsedRequest} objects\n     */\n    protected abstract HystrixCommand<BatchReturnType> createCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    /**\n     * Override to split (shard) a batch of requests into multiple batches that will each call <code>createCommand</code> separately.\n     * <p>\n     * The purpose of this is to allow collapsing to work for services that have sharded backends and batch executions that need to be shard-aware.\n     * <p>\n     * For example, a batch of 100 requests could be split into 4 different batches sharded on name (ie. a-g, h-n, o-t, u-z) that each result in a separate {@link HystrixCommand} being created and\n     * executed for them.\n     * <p>\n     * By default this method does nothing to the Collection and is a pass-thru.\n     * \n     * @param requests\n     *            {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} containing {@link CollapsedRequest} objects containing the arguments of each request collapsed in this batch.\n     * @return Collection of {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} objects sharded according to business rules.\n     *         <p>The CollapsedRequest instances should not be modified or wrapped as the CollapsedRequest instance object contains state information needed to complete the execution.\n     */\n    protected Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shardRequests(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n        return Collections.singletonList(requests);\n    }\n\n    /**\n     * Executed after the {@link HystrixCommand}{@code <BatchReturnType>} command created by {@link #createCommand} finishes processing (unless it fails) for mapping the {@code <BatchReturnType>} to\n     * the list of {@code CollapsedRequest<ResponseType, RequestArgumentType>} objects.\n     * <p>\n     * IMPORTANT IMPLEMENTATION DETAIL => The expected contract (responsibilities) of this method implementation is:\n     * <p>\n     * <ul>\n     * <li>ALL {@link CollapsedRequest} objects must have either a response or exception set on them even if the response is NULL\n     * otherwise the user thread waiting on the response will think a response was never received and will either block indefinitely or timeout while waiting.</li>\n     * <ul>\n     * <li>Setting a response is done via {@link CollapsedRequest#setResponse(Object)}</li>\n     * <li>Setting an exception is done via {@link CollapsedRequest#setException(Exception)}</li>\n     * </ul>\n     * </ul>\n     * <p>\n     * Common code when {@code <BatchReturnType>} is {@code List<ResponseType>} is:\n     * <p>\n     * \n     * <pre>\n     * int count = 0;\n     * for ({@code CollapsedRequest<ResponseType, RequestArgumentType>} request : requests) {\n     * &nbsp;&nbsp;&nbsp;&nbsp; request.setResponse(batchResponse.get(count++));\n     * }\n     * </pre>\n     * \n     * For example if the types were {@code <List<String>, String, String>}:\n     * <p>\n     * \n     * <pre>\n     * int count = 0;\n     * for ({@code CollapsedRequest<String, String>} request : requests) {\n     * &nbsp;&nbsp;&nbsp;&nbsp; request.setResponse(batchResponse.get(count++));\n     * }\n     * </pre>\n     * \n     * @param batchResponse\n     *            The {@code <BatchReturnType>} returned from the {@link HystrixCommand}{@code <BatchReturnType>} command created by {@link #createCommand}.\n     *            <p>\n     * \n     * @param requests\n     *            {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} containing {@link CollapsedRequest} objects containing the arguments of each request collapsed in this batch.\n     *            <p>\n     *            The {@link CollapsedRequest#setResponse(Object)} or {@link CollapsedRequest#setException(Exception)} must be called on each {@link CollapsedRequest} in the Collection.\n     */\n    protected abstract void mapResponseToRequests(BatchReturnType batchResponse, Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    /**\n     * Used for asynchronous execution with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This eagerly starts execution the same as {@link #queue()} and {@link #execute()}.\n     * A lazy {@link Observable} can be obtained from {@link #toObservable()}.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * Use {@link #toObservable(rx.Scheduler)} to schedule the callback differently.\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through {@link #mapResponseToRequests}\n     *         to transform the {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> observe() {\n        // use a ReplaySubject to buffer the eagerly subscribed-to Observable\n        ReplaySubject<ResponseType> subject = ReplaySubject.create();\n        // eagerly kick off subscription\n        final Subscription underlyingSubscription = toObservable().subscribe(subject);\n        // return the subject that can be subscribed to later while the execution has already started\n        return subject.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                underlyingSubscription.unsubscribe();\n            }\n        });\n    }\n\n    /**\n     * A lazy {@link Observable} that will execute when subscribed to.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that lazily executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through\n     *         {@link #mapResponseToRequests} to transform the {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> toObservable() {\n        // when we callback with the data we want to do the work\n        // on a separate thread than the one giving us the callback\n        return toObservable(Schedulers.computation());\n    }\n\n    /**\n     * A lazy {@link Observable} that will execute when subscribed to.\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @param observeOn\n     *            The {@link Scheduler} to execute callbacks on.\n     * @return {@code Observable<R>} that lazily executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through\n     *         {@link #mapResponseToRequests} to transform the {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> toObservable(Scheduler observeOn) {\n        return Observable.defer(new Func0<Observable<ResponseType>>() {\n            @Override\n            public Observable<ResponseType> call() {\n                final boolean isRequestCacheEnabled = getProperties().requestCacheEnabled().get();\n                final String cacheKey = getCacheKey();\n\n                /* try from cache first */\n                if (isRequestCacheEnabled) {\n                    HystrixCachedObservable<ResponseType> fromCache = requestCache.get(cacheKey);\n                    if (fromCache != null) {\n                        metrics.markResponseFromCache();\n                        return fromCache.toObservable();\n                    }\n                }\n\n                RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> requestCollapser = collapserFactory.getRequestCollapser(collapserInstanceWrapper);\n                Observable<ResponseType> response = requestCollapser.submitRequest(getRequestArgument());\n\n                if (isRequestCacheEnabled && cacheKey != null) {\n                    HystrixCachedObservable<ResponseType> toCache = HystrixCachedObservable.from(response);\n                    HystrixCachedObservable<ResponseType> fromCache = requestCache.putIfAbsent(cacheKey, toCache);\n                    if (fromCache == null) {\n                        return toCache.toObservable();\n                    } else {\n                        toCache.unsubscribe();\n                        return fromCache.toObservable();\n                    }\n                }\n                return response;\n            }\n        });\n    }\n\n    /**\n     * Used for synchronous execution.\n     * <p>\n     * If {@link Scope#REQUEST} is being used then synchronous execution will only result in collapsing if other threads are running within the same scope.\n     * \n     * @return ResponseType\n     *         Result of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through {@link #mapResponseToRequests} to transform the {@code <BatchReturnType>} into\n     *         {@code <ResponseType>}\n     * @throws HystrixRuntimeException\n     *             if an error occurs and a fallback cannot be retrieved\n     */\n    public ResponseType execute() {\n        try {\n            return queue().get();\n        } catch (Throwable e) {\n            if (e instanceof HystrixRuntimeException) {\n                throw (HystrixRuntimeException) e;\n            }\n            // if we have an exception we know about we'll throw it directly without the threading wrapper exception\n            if (e.getCause() instanceof HystrixRuntimeException) {\n                throw (HystrixRuntimeException) e.getCause();\n            }\n            // we don't know what kind of exception this is so create a generic message and throw a new HystrixRuntimeException\n            String message = getClass().getSimpleName() + \" HystrixCollapser failed while executing.\";\n            logger.debug(message, e); // debug only since we're throwing the exception and someone higher will do something with it\n            //TODO should this be made a HystrixRuntimeException?\n            throw new RuntimeException(message, e);\n        }\n    }\n\n    /**\n     * Used for asynchronous execution.\n     * <p>\n     * This will queue up the command and return a Future to get the result once it completes.\n     * \n     * @return ResponseType\n     *         Result of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through {@link #mapResponseToRequests} to transform the {@code <BatchReturnType>} into\n     *         {@code <ResponseType>}\n     * @throws HystrixRuntimeException\n     *             within an <code>ExecutionException.getCause()</code> (thrown by {@link Future#get}) if an error occurs and a fallback cannot be retrieved\n     */\n    public Future<ResponseType> queue() {\n        return toObservable()\n                .toBlocking()\n                .toFuture();\n    }\n\n    /**\n     * Key to be used for request caching.\n     * <p>\n     * By default this returns null which means \"do not cache\".\n     * <p>\n     * To enable caching override this method and return a string key uniquely representing the state of a command instance.\n     * <p>\n     * If multiple command instances in the same request scope match keys then only the first will be executed and all others returned from cache.\n     * \n     * @return String cacheKey or null if not to cache\n     */\n    protected String getCacheKey() {\n        return null;\n    }\n\n    /**\n     * Clears all state. If new requests come in instances will be recreated and metrics started from scratch.\n     */\n    /* package */static void reset() {\n        RequestCollapserFactory.reset();\n    }\n\n    private static String getDefaultNameFromClass(@SuppressWarnings(\"rawtypes\") Class<? extends HystrixCollapser> cls) {\n        String fromCache = defaultNameCache.get(cls);\n        if (fromCache != null) {\n            return fromCache;\n        }\n        // generate the default\n        // default HystrixCommandKey to use if the method is not overridden\n        String name = cls.getSimpleName();\n        if (name.equals(\"\")) {\n            // we don't have a SimpleName (anonymous inner class) so use the full class name\n            name = cls.getName();\n            name = name.substring(name.lastIndexOf('.') + 1, name.length());\n        }\n        defaultNameCache.put(cls, name);\n        return name;\n    }\n\n    /**\n     * A request argument RequestArgumentType that was collapsed for batch processing and needs a response ResponseType set on it by the <code>executeBatch</code> implementation.\n     */\n    public interface CollapsedRequest<ResponseType, RequestArgumentType> {\n        /**\n         * The request argument passed into the {@link HystrixCollapser} instance constructor which was then collapsed.\n         * \n         * @return RequestArgumentType\n         */\n        RequestArgumentType getArgument();\n\n        /**\n         * This corresponds in a OnNext(Response); OnCompleted pair of emissions.  It represents a single-value usecase.\n         *\n         * @throws IllegalStateException\n         *             if called more than once or after setException/setComplete.\n         * @param response\n         *            ResponseType\n         */\n        void setResponse(ResponseType response);\n\n        /**\n         * When invoked, any Observer will be OnNexted this value\n         * @throws IllegalStateException\n         *             if called after setException/setResponse/setComplete.\n         * @param response\n         */\n        void emitResponse(ResponseType response);\n\n        /**\n         * When set, any Observer will be OnErrored this exception\n         * \n         * @param exception exception to set on response\n         * @throws IllegalStateException\n         *             if called more than once or after setResponse/setComplete.\n         */\n        void setException(Exception exception);\n\n        /**\n         * When set, any Observer will have an OnCompleted emitted.\n         * The intent is to use if after a series of emitResponses\n         *\n         * Note that, unlike the other 3 methods above, this method does not throw an IllegalStateException.\n         * This allows Hystrix-core to unilaterally call it without knowing the internal state.\n         */\n        void setComplete();\n    }\n\n    /**\n     * Fluent interface for arguments to the {@link HystrixCollapser} constructor.\n     * <p>\n     * The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods.\n     * <p>\n     * Example:\n     * <pre> {@code\n     *  Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey(\"CollapserName\"))\n                .andScope(Scope.REQUEST);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    public static class Setter {\n        private final HystrixCollapserKey collapserKey;\n        private Scope scope = Scope.REQUEST; // default if nothing is set\n        private HystrixCollapserProperties.Setter propertiesSetter;\n\n        private Setter(HystrixCollapserKey collapserKey) {\n            this.collapserKey = collapserKey;\n        }\n\n        /**\n         * Setter factory method containing required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param collapserKey\n         *            {@link HystrixCollapserKey} that identifies this collapser and provides the key used for retrieving properties, request caches, publishing metrics etc.\n         * @return Setter for fluent interface via method chaining\n         */\n        public static Setter withCollapserKey(HystrixCollapserKey collapserKey) {\n            return new Setter(collapserKey);\n        }\n\n        /**\n         * {@link Scope} defining what scope the collapsing should occur within\n         * \n         * @param scope\n         * \n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andScope(Scope scope) {\n            this.scope = scope;\n            return this;\n        }\n\n        /**\n         * @param propertiesSetter\n         *            {@link HystrixCollapserProperties.Setter} that allows instance specific property overrides (which can then be overridden by dynamic properties, see\n         *            {@link HystrixPropertiesStrategy} for\n         *            information on order of precedence).\n         *            <p>\n         *            Will use defaults if left NULL.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter propertiesSetter) {\n            this.propertiesSetter = propertiesSetter;\n            return this;\n        }\n\n    }\n\n    // this is a micro-optimization but saves about 1-2microseconds (on 2011 MacBook Pro) \n    // on the repetitive string processing that will occur on the same classes over and over again\n    @SuppressWarnings(\"rawtypes\")\n    private static ConcurrentHashMap<Class<? extends HystrixCollapser>, String> defaultNameCache = new ConcurrentHashMap<Class<? extends HystrixCollapser>, String>();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapserKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * A key to represent a {@link HystrixCollapser} for monitoring, circuit-breakers, metrics publishing, caching and other such uses.\n * <p>\n * This interface is intended to work natively with Enums so that implementing code can be an enum that implements this interface.\n */\npublic interface HystrixCollapserKey {\n\n    /**\n     * The word 'name' is used instead of 'key' so that Enums can implement this interface and it work natively.\n     * \n     * @return String\n     */\n    public String name();\n\n    public static class Factory {\n\n        private Factory() {\n        }\n\n        // used to intern instances so we don't keep re-creating them millions of times for the same key\n        private static ConcurrentHashMap<String, HystrixCollapserKey> intern = new ConcurrentHashMap<String, HystrixCollapserKey>();\n\n        /**\n         * Retrieve (or create) an interned HystrixCollapserKey instance for a given name.\n         * \n         * @param name collapser name\n         * @return HystrixCollapserKey instance that is interned (cached) so a given name will always retrieve the same instance.\n         */\n        public static HystrixCollapserKey asKey(String name) {\n            HystrixCollapserKey k = intern.get(name);\n            if (k == null) {\n                intern.putIfAbsent(name, new HystrixCollapserKeyDefault(name));\n            }\n            return intern.get(name);\n        }\n\n        private static class HystrixCollapserKeyDefault implements HystrixCollapserKey {\n\n            private String name;\n\n            private HystrixCollapserKeyDefault(String name) {\n                this.name = name;\n            }\n\n            @Override\n            public String name() {\n                return name;\n            }\n            \n            @Override\n            public String toString() {\n            \treturn name;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapserMetrics.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.metric.HystrixCollapserEvent;\nimport com.netflix.hystrix.metric.HystrixThreadEventStream;\nimport com.netflix.hystrix.metric.consumer.CumulativeCollapserEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingCollapserBatchSizeDistributionStream;\nimport com.netflix.hystrix.metric.consumer.RollingCollapserEventCounterStream;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func2;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Used by {@link HystrixCollapser} to record metrics.\n * {@link HystrixEventNotifier} not hooked up yet.  It may be in the future.\n */\npublic class HystrixCollapserMetrics extends HystrixMetrics {\n\n    @SuppressWarnings(\"unused\")\n    private static final Logger logger = LoggerFactory.getLogger(HystrixCollapserMetrics.class);\n\n    // String is HystrixCollapserKey.name() (we can't use HystrixCollapserKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixCollapserMetrics> metrics = new ConcurrentHashMap<String, HystrixCollapserMetrics>();\n\n    /**\n     * Get or create the {@link HystrixCollapserMetrics} instance for a given {@link HystrixCollapserKey}.\n     * <p>\n     * This is thread-safe and ensures only 1 {@link HystrixCollapserMetrics} per {@link HystrixCollapserKey}.\n     * \n     * @param key\n     *            {@link HystrixCollapserKey} of {@link HystrixCollapser} instance requesting the {@link HystrixCollapserMetrics}\n     * @return {@link HystrixCollapserMetrics}\n     */\n    public static HystrixCollapserMetrics getInstance(HystrixCollapserKey key, HystrixCollapserProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixCollapserMetrics collapserMetrics = metrics.get(key.name());\n        if (collapserMetrics != null) {\n            return collapserMetrics;\n        }\n        // it doesn't exist so we need to create it\n        collapserMetrics = new HystrixCollapserMetrics(key, properties);\n        // attempt to store it (race other threads)\n        HystrixCollapserMetrics existing = metrics.putIfAbsent(key.name(), collapserMetrics);\n        if (existing == null) {\n            // we won the thread-race to store the instance we created\n            return collapserMetrics;\n        } else {\n            // we lost so return 'existing' and let the one we created be garbage collected\n            return existing;\n        }\n    }\n\n    /**\n     * All registered instances of {@link HystrixCollapserMetrics}\n     * \n     * @return {@code Collection<HystrixCollapserMetrics>}\n     */\n    public static Collection<HystrixCollapserMetrics> getInstances() {\n        return Collections.unmodifiableCollection(metrics.values());\n    }\n\n    private static final HystrixEventType.Collapser[] ALL_EVENT_TYPES = HystrixEventType.Collapser.values();\n\n    public static final Func2<long[], HystrixCollapserEvent, long[]> appendEventToBucket = new Func2<long[], HystrixCollapserEvent, long[]>() {\n        @Override\n        public long[] call(long[] initialCountArray, HystrixCollapserEvent collapserEvent) {\n            HystrixEventType.Collapser eventType = collapserEvent.getEventType();\n            int count = collapserEvent.getCount();\n            initialCountArray[eventType.ordinal()] += count;\n            return initialCountArray;\n        }\n    };\n\n    public static final Func2<long[], long[], long[]> bucketAggregator = new Func2<long[], long[], long[]>() {\n        @Override\n        public long[] call(long[] cumulativeEvents, long[] bucketEventCounts) {\n            for (HystrixEventType.Collapser eventType: ALL_EVENT_TYPES) {\n                cumulativeEvents[eventType.ordinal()] += bucketEventCounts[eventType.ordinal()];\n            }\n            return cumulativeEvents;\n        }\n    };\n\n    /**\n     * Clears all state from metrics. If new requests come in instances will be recreated and metrics started from scratch.\n     */\n    /* package */ static void reset() {\n        metrics.clear();\n    }\n\n    private final HystrixCollapserKey collapserKey;\n    private final HystrixCollapserProperties properties;\n\n    private final RollingCollapserEventCounterStream rollingCollapserEventCounterStream;\n    private final CumulativeCollapserEventCounterStream cumulativeCollapserEventCounterStream;\n    private final RollingCollapserBatchSizeDistributionStream rollingCollapserBatchSizeDistributionStream;\n\n    /* package */HystrixCollapserMetrics(HystrixCollapserKey key, HystrixCollapserProperties properties) {\n        super(null);\n        this.collapserKey = key;\n        this.properties = properties;\n\n        rollingCollapserEventCounterStream = RollingCollapserEventCounterStream.getInstance(key, properties);\n        cumulativeCollapserEventCounterStream = CumulativeCollapserEventCounterStream.getInstance(key, properties);\n        rollingCollapserBatchSizeDistributionStream = RollingCollapserBatchSizeDistributionStream.getInstance(key, properties);\n    }\n\n    /**\n     * {@link HystrixCollapserKey} these metrics represent.\n     * \n     * @return HystrixCollapserKey\n     */\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserKey;\n    }\n\n    public HystrixCollapserProperties getProperties() {\n        return properties;\n    }\n\n    public long getRollingCount(HystrixEventType.Collapser collapserEventType) {\n        return rollingCollapserEventCounterStream.getLatest(collapserEventType);\n    }\n\n    public long getCumulativeCount(HystrixEventType.Collapser collapserEventType) {\n        return cumulativeCollapserEventCounterStream.getLatest(collapserEventType);\n    }\n\n    @Override\n    public long getCumulativeCount(HystrixRollingNumberEvent event) {\n        return getCumulativeCount(HystrixEventType.Collapser.from(event));\n    }\n\n    @Override\n    public long getRollingCount(HystrixRollingNumberEvent event) {\n        return getRollingCount(HystrixEventType.Collapser.from(event));\n    }\n\n    /**\n     * Retrieve the batch size for the {@link HystrixCollapser} being invoked at a given percentile.\n     * <p>\n     * Percentile capture and calculation is configured via {@link HystrixCollapserProperties#metricsRollingStatisticalWindowInMilliseconds()} and other related properties.\n     *\n     * @param percentile\n     *            Percentile such as 50, 99, or 99.5.\n     * @return batch size\n     */\n    public int getBatchSizePercentile(double percentile) {\n        return rollingCollapserBatchSizeDistributionStream.getLatestPercentile(percentile);\n    }\n\n    public int getBatchSizeMean() {\n        return rollingCollapserBatchSizeDistributionStream.getLatestMean();\n    }\n\n    /**\n     * Retrieve the shard size for the {@link HystrixCollapser} being invoked at a given percentile.\n     * <p>\n     * Percentile capture and calculation is configured via {@link HystrixCollapserProperties#metricsRollingStatisticalWindowInMilliseconds()} and other related properties.\n     *\n     * @param percentile\n     *            Percentile such as 50, 99, or 99.5.\n     * @return batch size\n     */\n    public int getShardSizePercentile(double percentile) {\n        return 0;\n        //return rollingCollapserUsageDistributionStream.getLatestBatchSizePercentile(percentile);\n    }\n\n    public int getShardSizeMean() {\n        return 0;\n        //return percentileShardSize.getMean();\n    }\n\n    public void markRequestBatched() {\n    }\n\n    public void markResponseFromCache() {\n        HystrixThreadEventStream.getInstance().collapserResponseFromCache(collapserKey);\n    }\n\n    public void markBatch(int batchSize) {\n        HystrixThreadEventStream.getInstance().collapserBatchExecuted(collapserKey, batchSize);\n    }\n\n    public void markShards(int numShards) {\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapserProperties.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean;\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forString;\n\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixRollingNumber;\nimport com.netflix.hystrix.util.HystrixRollingPercentile;\n\n/**\n * Properties for instances of {@link HystrixCollapser}.\n * <p>\n * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)\n */\npublic abstract class HystrixCollapserProperties {\n\n    /* defaults */\n    private static final Integer default_maxRequestsInBatch = Integer.MAX_VALUE;\n    private static final Integer default_timerDelayInMilliseconds = 10;\n    private static final Boolean default_requestCacheEnabled = true;\n    /* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)\n    private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second\n    private static final Boolean default_metricsRollingPercentileEnabled = true;\n    private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile\n    private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)\n    private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket\n\n    private final HystrixProperty<Integer> maxRequestsInBatch;\n    private final HystrixProperty<Integer> timerDelayInMilliseconds;\n    private final HystrixProperty<Boolean> requestCacheEnabled;\n    private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds; // milliseconds back that will be tracked\n    private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow\n    private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; // Whether monitoring should be enabled\n    private final HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds; // number of milliseconds that will be tracked in RollingPercentile\n    private final HystrixProperty<Integer> metricsRollingPercentileWindowBuckets; // number of buckets percentileWindow will be divided into\n    private final HystrixProperty<Integer> metricsRollingPercentileBucketSize; // how many values will be stored in each percentileWindowBucket\n\n    protected HystrixCollapserProperties(HystrixCollapserKey collapserKey) {\n        this(collapserKey, new Setter(), \"hystrix\");\n    }\n\n    protected HystrixCollapserProperties(HystrixCollapserKey collapserKey, Setter builder) {\n        this(collapserKey, builder, \"hystrix\");\n    }\n\n    protected HystrixCollapserProperties(HystrixCollapserKey key, Setter builder, String propertyPrefix) {\n        this.maxRequestsInBatch = getProperty(propertyPrefix, key, \"maxRequestsInBatch\", builder.getMaxRequestsInBatch(), default_maxRequestsInBatch);\n        this.timerDelayInMilliseconds = getProperty(propertyPrefix, key, \"timerDelayInMilliseconds\", builder.getTimerDelayInMilliseconds(), default_timerDelayInMilliseconds);\n        this.requestCacheEnabled = getProperty(propertyPrefix, key, \"requestCache.enabled\", builder.getRequestCacheEnabled(), default_requestCacheEnabled);\n        this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, \"metrics.rollingStats.timeInMilliseconds\", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);\n        this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, \"metrics.rollingStats.numBuckets\", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);\n        this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.enabled\", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);\n        this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.timeInMilliseconds\", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);\n        this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.numBuckets\", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);\n        this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.bucketSize\", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);\n    }\n\n    private static HystrixProperty<Integer> getProperty(String propertyPrefix, HystrixCollapserKey key, String instanceProperty, Integer builderOverrideValue, Integer defaultValue) {\n        return forInteger()\n              .add(propertyPrefix + \".collapser.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n              .add(propertyPrefix + \".collapser.default.\" + instanceProperty, defaultValue)\n              .build();\n              \n\n    }\n\n    private static HystrixProperty<Boolean> getProperty(String propertyPrefix, HystrixCollapserKey key, String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) {\n        return forBoolean()\n                .add(propertyPrefix + \".collapser.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".collapser.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    /**\n     * Whether request caching is enabled for {@link HystrixCollapser#execute} and {@link HystrixCollapser#queue} invocations.\n     *\n     * Deprecated as of 1.4.0-RC7 in favor of requestCacheEnabled() (to match {@link HystrixCommandProperties#requestCacheEnabled()}\n     *\n     * @return {@code HystrixProperty<Boolean>}\n     */\n    @Deprecated\n    public HystrixProperty<Boolean> requestCachingEnabled() {\n        return requestCacheEnabled;\n    }\n\n    /**\n     * Whether request caching is enabled for {@link HystrixCollapser#execute} and {@link HystrixCollapser#queue} invocations.\n     *\n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> requestCacheEnabled() {\n        return requestCacheEnabled;\n    }\n\n    /**\n     * The maximum number of requests allowed in a batch before triggering a batch execution.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> maxRequestsInBatch() {\n        return maxRequestsInBatch;\n    }\n\n    /**\n     * The number of milliseconds between batch executions (unless {@link #maxRequestsInBatch} is hit which will cause a batch to execute early.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> timerDelayInMilliseconds() {\n        return timerDelayInMilliseconds;\n    }\n\n    /**\n     * Duration of statistical rolling window in milliseconds. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCommandMetrics}.\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds() {\n        return metricsRollingStatisticalWindowInMilliseconds;\n    }\n\n    /**\n     * Number of buckets the rolling statistical window is broken into. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCollapserMetrics}.\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets() {\n        return metricsRollingStatisticalWindowBuckets;\n    }\n\n    /**\n     * Whether percentile metrics should be captured using {@link HystrixRollingPercentile} inside {@link HystrixCollapserMetrics}.\n     *\n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> metricsRollingPercentileEnabled() {\n        return metricsRollingPercentileEnabled;\n    }\n\n    /**\n     * Duration of percentile rolling window in milliseconds. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCollapserMetrics}.\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds() {\n        return metricsRollingPercentileWindowInMilliseconds;\n    }\n\n    /**\n     * Number of buckets the rolling percentile window is broken into. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCollapserMetrics}.\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileWindowBuckets() {\n        return metricsRollingPercentileWindowBuckets;\n    }\n\n    /**\n     * Maximum number of values stored in each bucket of the rolling percentile. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCollapserMetrics}.\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileBucketSize() {\n        return metricsRollingPercentileBucketSize;\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     */\n    public static Setter Setter() {\n        return new Setter();\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     * Groovy has a bug (GROOVY-6286) which does not allow method names and inner classes to have the same name\n     * This method fixes Issue #967 and allows Groovy consumers to choose this method and not trigger the bug\n     */\n    public static Setter defaultSetter() {\n        return Setter();\n    }\n\n    /**\n     * Fluent interface that allows chained setting of properties that can be passed into a {@link HystrixCollapser} constructor to inject instance specific property overrides.\n     * <p>\n     * See {@link HystrixPropertiesStrategy} for more information on order of precedence.\n     * <p>\n     * Example:\n     * <p>\n     * <pre> {@code\n     * HystrixCollapserProperties.Setter()\n     *           .setMaxRequestsInBatch(100)\n     *           .setTimerDelayInMilliseconds(10);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    public static class Setter {\n        @Deprecated private Boolean collapsingEnabled = null;\n        private Integer maxRequestsInBatch = null;\n        private Integer timerDelayInMilliseconds = null;\n        private Boolean requestCacheEnabled = null;\n        private Integer metricsRollingStatisticalWindowInMilliseconds = null;\n        private Integer metricsRollingStatisticalWindowBuckets = null;\n        private Integer metricsRollingPercentileBucketSize = null;\n        private Boolean metricsRollingPercentileEnabled = null;\n        private Integer metricsRollingPercentileWindowInMilliseconds = null;\n        private Integer metricsRollingPercentileWindowBuckets = null;\n\n        private Setter() {\n        }\n\n        /**\n         * Deprecated because the collapsingEnabled setting doesn't do anything.\n         */\n        @Deprecated\n        public Boolean getCollapsingEnabled() {\n            return collapsingEnabled;\n        }\n\n        public Integer getMaxRequestsInBatch() {\n            return maxRequestsInBatch;\n        }\n\n        public Integer getTimerDelayInMilliseconds() {\n            return timerDelayInMilliseconds;\n        }\n\n        public Boolean getRequestCacheEnabled() {\n            return requestCacheEnabled;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowInMilliseconds() {\n            return metricsRollingStatisticalWindowInMilliseconds;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowBuckets() {\n            return metricsRollingStatisticalWindowBuckets;\n        }\n\n        public Integer getMetricsRollingPercentileBucketSize() {\n            return metricsRollingPercentileBucketSize;\n        }\n\n        public Boolean getMetricsRollingPercentileEnabled() {\n            return metricsRollingPercentileEnabled;\n        }\n\n        public Integer getMetricsRollingPercentileWindowInMilliseconds() {\n            return metricsRollingPercentileWindowInMilliseconds;\n        }\n\n        public Integer getMetricsRollingPercentileWindowBuckets() {\n            return metricsRollingPercentileWindowBuckets;\n        }\n\n        /**\n         * Deprecated because the collapsingEnabled setting doesn't do anything.\n         */\n        @Deprecated\n        public Setter withCollapsingEnabled(boolean value) {\n            this.collapsingEnabled = value;\n            return this;\n        }\n\n        public Setter withMaxRequestsInBatch(int value) {\n            this.maxRequestsInBatch = value;\n            return this;\n        }\n\n        public Setter withTimerDelayInMilliseconds(int value) {\n            this.timerDelayInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withRequestCacheEnabled(boolean value) {\n            this.requestCacheEnabled = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowInMilliseconds(int value) {\n            this.metricsRollingStatisticalWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowBuckets(int value) {\n            this.metricsRollingStatisticalWindowBuckets = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileBucketSize(int value) {\n            this.metricsRollingPercentileBucketSize = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileEnabled(boolean value) {\n            this.metricsRollingPercentileEnabled = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileWindowInMilliseconds(int value) {\n            this.metricsRollingPercentileWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileWindowBuckets(int value) {\n            this.metricsRollingPercentileWindowBuckets = value;\n            return this;\n        }\n\n        /**\n         * Base properties for unit testing.\n         */\n        /* package */static Setter getUnitTestPropertiesBuilder() {\n            return new Setter()\n                    .withMaxRequestsInBatch(Integer.MAX_VALUE)\n                    .withTimerDelayInMilliseconds(10)\n                    .withRequestCacheEnabled(true);\n        }\n\n        /**\n         * Return a static representation of the properties with values from the Builder so that UnitTests can create properties that are not affected by the actual implementations which pick up their\n         * values dynamically.\n         * \n         * @param builder collapser properties builder\n         * @return HystrixCollapserProperties\n         */\n        /* package */static HystrixCollapserProperties asMock(final Setter builder) {\n            return new HystrixCollapserProperties(TestHystrixCollapserKey.TEST) {\n\n                @Override\n                public HystrixProperty<Boolean> requestCachingEnabled() {\n                    return HystrixProperty.Factory.asProperty(builder.requestCacheEnabled);\n                }\n\n                @Override\n                public HystrixProperty<Integer> maxRequestsInBatch() {\n                    return HystrixProperty.Factory.asProperty(builder.maxRequestsInBatch);\n                }\n\n                @Override\n                public HystrixProperty<Integer> timerDelayInMilliseconds() {\n                    return HystrixProperty.Factory.asProperty(builder.timerDelayInMilliseconds);\n                }\n\n            };\n        }\n\n        private static enum TestHystrixCollapserKey implements HystrixCollapserKey {\n            TEST\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.netflix.hystrix.util.Exceptions;\nimport rx.Observable;\nimport rx.functions.Action0;\n\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException.FailureType;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport rx.functions.Func0;\n\n/**\n * Used to wrap code that will execute potentially risky functionality (typically meaning a service call over the network)\n * with fault and latency tolerance, statistics and performance metrics capture, circuit breaker and bulkhead functionality.\n * This command is essentially a blocking command but provides an Observable facade if used with observe()\n * \n * @param <R>\n *            the return type\n * \n * @ThreadSafe\n */\npublic abstract class HystrixCommand<R> extends AbstractCommand<R> implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> {\n\n\n    /**\n     * Construct a {@link HystrixCommand} with defined {@link HystrixCommandGroupKey}.\n     * <p>\n     * The {@link HystrixCommandKey} will be derived from the implementing class name.\n     * \n     * @param group\n     *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n     *            <p>\n     *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interact with,\n     *            common business purpose etc.\n     */\n    protected HystrixCommand(HystrixCommandGroupKey group) {\n        super(group, null, null, null, null, null, null, null, null, null, null, null);\n    }\n\n\n    /**\n     * Construct a {@link HystrixCommand} with defined {@link HystrixCommandGroupKey} and {@link HystrixThreadPoolKey}.\n     * <p>\n     * The {@link HystrixCommandKey} will be derived from the implementing class name.\n     *\n     * @param group\n     *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n     *            <p>\n     *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interact with,\n     *            common business purpose etc.\n     * @param threadPool\n     *            {@link HystrixThreadPoolKey} used to identify the thread pool in which a {@link HystrixCommand} executes.\n     */\n    protected HystrixCommand(HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {\n        super(group, null, threadPool, null, null, null, null, null, null, null, null, null);\n    }\n\n    /**\n     * Construct a {@link HystrixCommand} with defined {@link HystrixCommandGroupKey} and thread timeout\n     * <p>\n     * The {@link HystrixCommandKey} will be derived from the implementing class name.\n     *\n     * @param group\n     *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n     *            <p>\n     *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interact with,\n     *            common business purpose etc.\n     * @param executionIsolationThreadTimeoutInMilliseconds\n     *            Time in milliseconds at which point the calling thread will timeout (using {@link Future#get}) and walk away from the executing thread.\n     */\n    protected HystrixCommand(HystrixCommandGroupKey group, int executionIsolationThreadTimeoutInMilliseconds) {\n        super(group, null, null, null, null, HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(executionIsolationThreadTimeoutInMilliseconds), null, null, null, null, null, null);\n    }\n\n    /**\n     * Construct a {@link HystrixCommand} with defined {@link HystrixCommandGroupKey}, {@link HystrixThreadPoolKey}, and thread timeout.\n     * <p>\n     * The {@link HystrixCommandKey} will be derived from the implementing class name.\n     *\n     * @param group\n     *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n     *            <p>\n     *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interact with,\n     *            common business purpose etc.\n     * @param threadPool\n     *            {@link HystrixThreadPool} used to identify the thread pool in which a {@link HystrixCommand} executes.\n     * @param executionIsolationThreadTimeoutInMilliseconds\n     *            Time in milliseconds at which point the calling thread will timeout (using {@link Future#get}) and walk away from the executing thread.\n     */\n    protected HystrixCommand(HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool, int executionIsolationThreadTimeoutInMilliseconds) {\n        super(group, null, threadPool, null, null, HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(executionIsolationThreadTimeoutInMilliseconds), null, null, null, null, null, null);\n    }\n\n    /**\n     * Construct a {@link HystrixCommand} with defined {@link Setter} that allows injecting property and strategy overrides and other optional arguments.\n     * <p>\n     * NOTE: The {@link HystrixCommandKey} is used to associate a {@link HystrixCommand} with {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and other objects.\n     * <p>\n     * Do not create multiple {@link HystrixCommand} implementations with the same {@link HystrixCommandKey} but different injected default properties as the first instantiated will win.\n     * <p>\n     * Properties passed in via {@link Setter#andCommandPropertiesDefaults} or {@link Setter#andThreadPoolPropertiesDefaults} are cached for the given {@link HystrixCommandKey} for the life of the JVM\n     * or until {@link Hystrix#reset()} is called. Dynamic properties allow runtime changes. Read more on the <a href=\"https://github.com/Netflix/Hystrix/wiki/Configuration\">Hystrix Wiki</a>.\n     * \n     * @param setter\n     *            Fluent interface for constructor arguments\n     */\n    protected HystrixCommand(Setter setter) {\n        // use 'null' to specify use the default\n        this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);\n    }\n\n    /**\n     * Allow constructing a {@link HystrixCommand} with injection of most aspects of its functionality.\n     * <p>\n     * Some of these never have a legitimate reason for injection except in unit testing.\n     * <p>\n     * Most of the args will revert to a valid default if 'null' is passed in.\n     */\n    /* package for testing */HystrixCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,\n            HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,\n            HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,\n            HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {\n        super(group, key, threadPoolKey, circuitBreaker, threadPool, commandPropertiesDefaults, threadPoolPropertiesDefaults, metrics, fallbackSemaphore, executionSemaphore, propertiesStrategy, executionHook);\n    }\n\n    /**\n     * Fluent interface for arguments to the {@link HystrixCommand} constructor.\n     * <p>\n     * The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods.\n     * <p>\n     * Example:\n     * <pre> {@code\n     *  Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GroupName\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"CommandName\"));\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    final public static class Setter {\n\n        protected final HystrixCommandGroupKey groupKey;\n        protected HystrixCommandKey commandKey;\n        protected HystrixThreadPoolKey threadPoolKey;\n        protected HystrixCommandProperties.Setter commandPropertiesDefaults;\n        protected HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults;\n\n        /**\n         * Setter factory method containing required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param groupKey\n         *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n         *            <p>\n         *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace\n         *            with,\n         *            common business purpose etc.\n         */\n        protected Setter(HystrixCommandGroupKey groupKey) {\n            this.groupKey = groupKey;\n        }\n\n        /**\n         * Setter factory method with required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param groupKey\n         *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixCommand} objects.\n         *            <p>\n         *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace\n         *            with,\n         *            common business purpose etc.\n         */\n        public static Setter withGroupKey(HystrixCommandGroupKey groupKey) {\n            return new Setter(groupKey);\n        }\n\n        /**\n         * @param commandKey\n         *            {@link HystrixCommandKey} used to identify a {@link HystrixCommand} instance for statistics, circuit-breaker, properties, etc.\n         *            <p>\n         *            By default this will be derived from the instance class name.\n         *            <p>\n         *            NOTE: Every unique {@link HystrixCommandKey} will result in new instances of {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and {@link HystrixCommandProperties}.\n         *            Thus,\n         *            the number of variants should be kept to a finite and reasonable number to avoid high-memory usage or memory leaks.\n         *            <p>\n         *            Hundreds of keys is fine, tens of thousands is probably not.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCommandKey(HystrixCommandKey commandKey) {\n            this.commandKey = commandKey;\n            return this;\n        }\n\n        /**\n         * @param threadPoolKey\n         *            {@link HystrixThreadPoolKey} used to define which thread-pool this command should run in (when configured to run on separate threads via\n         *            {@link HystrixCommandProperties#executionIsolationStrategy()}).\n         *            <p>\n         *            By default this is derived from the {@link HystrixCommandGroupKey} but if injected this allows multiple commands to have the same {@link HystrixCommandGroupKey} but different\n         *            thread-pools.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andThreadPoolKey(HystrixThreadPoolKey threadPoolKey) {\n            this.threadPoolKey = threadPoolKey;\n            return this;\n        }\n\n        /**\n         * Optional\n         * \n         * @param commandPropertiesDefaults\n         *            {@link HystrixCommandProperties.Setter} with property overrides for this specific instance of {@link HystrixCommand}.\n         *            <p>\n         *            See the {@link HystrixPropertiesStrategy} JavaDocs for more information on properties and order of precedence.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) {\n            this.commandPropertiesDefaults = commandPropertiesDefaults;\n            return this;\n        }\n\n        /**\n         * Optional\n         * \n         * @param threadPoolPropertiesDefaults\n         *            {@link HystrixThreadPoolProperties.Setter} with property overrides for the {@link HystrixThreadPool} used by this specific instance of {@link HystrixCommand}.\n         *            <p>\n         *            See the {@link HystrixPropertiesStrategy} JavaDocs for more information on properties and order of precedence.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {\n            this.threadPoolPropertiesDefaults = threadPoolPropertiesDefaults;\n            return this;\n        }\n\n    }\n\n\tprivate final AtomicReference<Thread> executionThread = new AtomicReference<Thread>();\n\tprivate final AtomicBoolean interruptOnFutureCancel = new AtomicBoolean(false);\n\n\t/**\n     * Implement this method with code to be executed when {@link #execute()} or {@link #queue()} are invoked.\n     * \n     * @return R response type\n     * @throws Exception\n     *             if command execution fails\n     */\n    protected abstract R run() throws Exception;\n\n    /**\n     * If {@link #execute()} or {@link #queue()} fails in any way then this method will be invoked to provide an opportunity to return a fallback response.\n     * <p>\n     * This should do work that does not require network transport to produce.\n     * <p>\n     * In other words, this should be a static or cached result that can immediately be returned upon failure.\n     * <p>\n     * If network traffic is wanted for fallback (such as going to MemCache) then the fallback implementation should invoke another {@link HystrixCommand} instance that protects against that network\n     * access and possibly has another level of fallback that does not involve network access.\n     * <p>\n     * DEFAULT BEHAVIOR: It throws UnsupportedOperationException.\n     * \n     * @return R or throw UnsupportedOperationException if not implemented\n     */\n    protected R getFallback() {\n        throw new UnsupportedOperationException(\"No fallback available.\");\n    }\n\n    @Override\n    final protected Observable<R> getExecutionObservable() {\n        return Observable.defer(new Func0<Observable<R>>() {\n            @Override\n            public Observable<R> call() {\n                try {\n                    return Observable.just(run());\n                } catch (Throwable ex) {\n                    return Observable.error(ex);\n                }\n            }\n        }).doOnSubscribe(new Action0() {\n            @Override\n            public void call() {\n                // Save thread on which we get subscribed so that we can interrupt it later if needed\n                executionThread.set(Thread.currentThread());\n            }\n        });\n    }\n\n    @Override\n    final protected Observable<R> getFallbackObservable() {\n        return Observable.defer(new Func0<Observable<R>>() {\n            @Override\n            public Observable<R> call() {\n                try {\n                    return Observable.just(getFallback());\n                } catch (Throwable ex) {\n                    return Observable.error(ex);\n                }\n            }\n        });\n    }\n\n    /**\n     * Used for synchronous execution of command.\n     * \n     * @return R\n     *         Result of {@link #run()} execution or a fallback from {@link #getFallback()} if the command fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a failure occurs and a fallback cannot be retrieved\n     * @throws HystrixBadRequestException\n     *             if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public R execute() {\n        try {\n            return queue().get();\n        } catch (Exception e) {\n            throw Exceptions.sneakyThrow(decomposeException(e));\n        }\n    }\n\n    /**\n     * Used for asynchronous execution of command.\n     * <p>\n     * This will queue up the command on the thread pool and return an {@link Future} to get the result once it completes.\n     * <p>\n     * NOTE: If configured to not run in a separate thread, this will have the same effect as {@link #execute()} and will block.\n     * <p>\n     * We don't throw an exception but just flip to synchronous execution so code doesn't need to change in order to switch a command from running on a separate thread to the calling thread.\n     * \n     * @return {@code Future<R>} Result of {@link #run()} execution or a fallback from {@link #getFallback()} if the command fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Future.get()} in {@link ExecutionException#getCause()} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Future.get()} in {@link ExecutionException#getCause()} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Future<R> queue() {\n        /*\n         * The Future returned by Observable.toBlocking().toFuture() does not implement the\n         * interruption of the execution thread when the \"mayInterrupt\" flag of Future.cancel(boolean) is set to true;\n         * thus, to comply with the contract of Future, we must wrap around it.\n         */\n        final Future<R> delegate = toObservable().toBlocking().toFuture();\n    \t\n        final Future<R> f = new Future<R>() {\n\n            @Override\n            public boolean cancel(boolean mayInterruptIfRunning) {\n                if (delegate.isCancelled()) {\n                    return false;\n                }\n\n                if (HystrixCommand.this.getProperties().executionIsolationThreadInterruptOnFutureCancel().get()) {\n                    /*\n                     * The only valid transition here is false -> true. If there are two futures, say f1 and f2, created by this command\n                     * (which is super-weird, but has never been prohibited), and calls to f1.cancel(true) and to f2.cancel(false) are\n                     * issued by different threads, it's unclear about what value would be used by the time mayInterruptOnCancel is checked.\n                     * The most consistent way to deal with this scenario is to say that if *any* cancellation is invoked with interruption,\n                     * than that interruption request cannot be taken back.\n                     */\n                    interruptOnFutureCancel.compareAndSet(false, mayInterruptIfRunning);\n        \t\t}\n\n                final boolean res = delegate.cancel(interruptOnFutureCancel.get());\n\n                if (!isExecutionComplete() && interruptOnFutureCancel.get()) {\n                    final Thread t = executionThread.get();\n                    if (t != null && !t.equals(Thread.currentThread())) {\n                        t.interrupt();\n                    }\n                }\n\n                return res;\n\t\t\t}\n\n            @Override\n            public boolean isCancelled() {\n                return delegate.isCancelled();\n\t\t\t}\n\n            @Override\n            public boolean isDone() {\n                return delegate.isDone();\n\t\t\t}\n\n            @Override\n            public R get() throws InterruptedException, ExecutionException {\n                return delegate.get();\n            }\n\n            @Override\n            public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {\n                return delegate.get(timeout, unit);\n            }\n        \t\n        };\n\n        /* special handling of error states that throw immediately */\n        if (f.isDone()) {\n            try {\n                f.get();\n                return f;\n            } catch (Exception e) {\n                Throwable t = decomposeException(e);\n                if (t instanceof HystrixBadRequestException) {\n                    return f;\n                } else if (t instanceof HystrixRuntimeException) {\n                    HystrixRuntimeException hre = (HystrixRuntimeException) t;\n                    switch (hre.getFailureType()) {\n\t\t\t\t\tcase COMMAND_EXCEPTION:\n\t\t\t\t\tcase TIMEOUT:\n\t\t\t\t\t\t// we don't throw these types from queue() only from queue().get() as they are execution errors\n\t\t\t\t\t\treturn f;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// these are errors we throw from queue() as they as rejection type errors\n\t\t\t\t\t\tthrow hre;\n\t\t\t\t\t}\n                } else {\n                    throw Exceptions.sneakyThrow(t);\n                }\n            }\n        }\n\n        return f;\n    }\n\n    @Override\n    protected String getFallbackMethodName() {\n        return \"getFallback\";\n    }\n\n    @Override\n    protected boolean isFallbackUserDefined() {\n        Boolean containsFromMap = commandContainsFallback.get(commandKey);\n        if (containsFromMap != null) {\n            return containsFromMap;\n        } else {\n            Boolean toInsertIntoMap;\n            try {\n                getClass().getDeclaredMethod(\"getFallback\");\n                toInsertIntoMap = true;\n            } catch (NoSuchMethodException nsme) {\n                toInsertIntoMap = false;\n            }\n            commandContainsFallback.put(commandKey, toInsertIntoMap);\n            return toInsertIntoMap;\n        }\n    }\n\n    @Override\n    protected boolean commandIsScalar() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandGroupKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.util.InternMap;\n\n/**\n * A group name for a {@link HystrixCommand}. This is used for grouping together commands such as for reporting, alerting, dashboards or team/library ownership.\n * <p>\n * By default this will be used to define the {@link HystrixThreadPoolKey} unless a separate one is defined.\n * <p>\n * This interface is intended to work natively with Enums so that implementing code can have an enum with the owners that implements this interface.\n */\npublic interface HystrixCommandGroupKey extends HystrixKey {\n    class Factory {\n        private Factory() {\n        }\n\n        // used to intern instances so we don't keep re-creating them millions of times for the same key\n        private static final InternMap<String, HystrixCommandGroupDefault> intern\n                = new InternMap<String, HystrixCommandGroupDefault>(\n                new InternMap.ValueConstructor<String, HystrixCommandGroupDefault>() {\n                    @Override\n                    public HystrixCommandGroupDefault create(String key) {\n                        return new HystrixCommandGroupDefault(key);\n                    }\n                });\n\n\n        /**\n         * Retrieve (or create) an interned HystrixCommandGroup instance for a given name.\n         *\n         * @param name command group name\n         * @return HystrixCommandGroup instance that is interned (cached) so a given name will always retrieve the same instance.\n         */\n        public static HystrixCommandGroupKey asKey(String name) {\n           return intern.interned(name);\n        }\n\n        private static class HystrixCommandGroupDefault extends HystrixKey.HystrixKeyDefault implements HystrixCommandGroupKey {\n            public HystrixCommandGroupDefault(String name) {\n                super(name);\n            }\n        }\n\n        /* package-private */ static int getGroupCount() {\n            return intern.size();\n        }\n    }\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.util.InternMap;\n\n/**\n * A key to represent a {@link HystrixCommand} for monitoring, circuit-breakers, metrics publishing, caching and other such uses.\n * <p>\n * This interface is intended to work natively with Enums so that implementing code can be an enum that implements this interface.\n */\npublic interface HystrixCommandKey extends HystrixKey {\n    class Factory {\n        private Factory() {\n        }\n\n        // used to intern instances so we don't keep re-creating them millions of times for the same key\n        private static final InternMap<String, HystrixCommandKeyDefault> intern\n                = new InternMap<String, HystrixCommandKeyDefault>(\n                new InternMap.ValueConstructor<String, HystrixCommandKeyDefault>() {\n                    @Override\n                    public HystrixCommandKeyDefault create(String key) {\n                        return new HystrixCommandKeyDefault(key);\n                    }\n                });\n\n\n        /**\n         * Retrieve (or create) an interned HystrixCommandKey instance for a given name.\n         * \n         * @param name command name\n         * @return HystrixCommandKey instance that is interned (cached) so a given name will always retrieve the same instance.\n         */\n        public static HystrixCommandKey asKey(String name) {\n            return intern.interned(name);\n        }\n\n        private static class HystrixCommandKeyDefault extends HystrixKey.HystrixKeyDefault implements HystrixCommandKey {\n            public HystrixCommandKeyDefault(String name) {\n                super(name);\n            }\n        }\n\n        /* package-private */ static int getCommandCount() {\n            return intern.size();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandMetrics.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixThreadEventStream;\nimport com.netflix.hystrix.metric.consumer.CumulativeCommandEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.HealthCountsStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandLatencyDistributionStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandMaxConcurrencyStream;\nimport com.netflix.hystrix.metric.consumer.RollingCommandUserLatencyDistributionStream;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\nimport rx.functions.Func2;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Used by {@link HystrixCommand} to record metrics.\n */\npublic class HystrixCommandMetrics extends HystrixMetrics {\n\n    @SuppressWarnings(\"unused\")\n    private static final Logger logger = LoggerFactory.getLogger(HystrixCommandMetrics.class);\n\n    private static final HystrixEventType[] ALL_EVENT_TYPES = HystrixEventType.values();\n\n    public static final Func2<long[], HystrixCommandCompletion, long[]> appendEventToBucket = new Func2<long[], HystrixCommandCompletion, long[]>() {\n        @Override\n        public long[] call(long[] initialCountArray, HystrixCommandCompletion execution) {\n            ExecutionResult.EventCounts eventCounts = execution.getEventCounts();\n            for (HystrixEventType eventType: ALL_EVENT_TYPES) {\n                switch (eventType) {\n                    case EXCEPTION_THROWN: break; //this is just a sum of other anyway - don't do the work here\n                    default:\n                        initialCountArray[eventType.ordinal()] += eventCounts.getCount(eventType);\n                        break;\n                }\n            }\n            return initialCountArray;\n        }\n    };\n\n    public static final Func2<long[], long[], long[]> bucketAggregator = new Func2<long[], long[], long[]>() {\n        @Override\n        public long[] call(long[] cumulativeEvents, long[] bucketEventCounts) {\n            for (HystrixEventType eventType: ALL_EVENT_TYPES) {\n                switch (eventType) {\n                    case EXCEPTION_THROWN:\n                        for (HystrixEventType exceptionEventType: HystrixEventType.EXCEPTION_PRODUCING_EVENT_TYPES) {\n                            cumulativeEvents[eventType.ordinal()] += bucketEventCounts[exceptionEventType.ordinal()];\n                        }\n                        break;\n                    default:\n                        cumulativeEvents[eventType.ordinal()] += bucketEventCounts[eventType.ordinal()];\n                        break;\n                }\n            }\n            return cumulativeEvents;\n        }\n    };\n\n    // String is HystrixCommandKey.name() (we can't use HystrixCommandKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixCommandMetrics> metrics = new ConcurrentHashMap<String, HystrixCommandMetrics>();\n\n    /**\n     * Get or create the {@link HystrixCommandMetrics} instance for a given {@link HystrixCommandKey}.\n     * <p>\n     * This is thread-safe and ensures only 1 {@link HystrixCommandMetrics} per {@link HystrixCommandKey}.\n     * \n     * @param key\n     *            {@link HystrixCommandKey} of {@link HystrixCommand} instance requesting the {@link HystrixCommandMetrics}\n     * @param commandGroup\n     *            Pass-thru to {@link HystrixCommandMetrics} instance on first time when constructed\n     * @param properties\n     *            Pass-thru to {@link HystrixCommandMetrics} instance on first time when constructed\n     * @return {@link HystrixCommandMetrics}\n     */\n    public static HystrixCommandMetrics getInstance(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties) {\n        return getInstance(key, commandGroup, null, properties);\n    }\n\n    /**\n     * Get or create the {@link HystrixCommandMetrics} instance for a given {@link HystrixCommandKey}.\n     * <p>\n     * This is thread-safe and ensures only 1 {@link HystrixCommandMetrics} per {@link HystrixCommandKey}.\n     *\n     * @param key\n     *            {@link HystrixCommandKey} of {@link HystrixCommand} instance requesting the {@link HystrixCommandMetrics}\n     * @param commandGroup\n     *            Pass-thru to {@link HystrixCommandMetrics} instance on first time when constructed\n     * @param properties\n     *            Pass-thru to {@link HystrixCommandMetrics} instance on first time when constructed\n     * @return {@link HystrixCommandMetrics}\n     */\n    public static HystrixCommandMetrics getInstance(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixThreadPoolKey threadPoolKey, HystrixCommandProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixCommandMetrics commandMetrics = metrics.get(key.name());\n        if (commandMetrics != null) {\n            return commandMetrics;\n        } else {\n            synchronized (HystrixCommandMetrics.class) {\n                HystrixCommandMetrics existingMetrics = metrics.get(key.name());\n                if (existingMetrics != null) {\n                    return existingMetrics;\n                } else {\n                    HystrixThreadPoolKey nonNullThreadPoolKey;\n                    if (threadPoolKey == null) {\n                        nonNullThreadPoolKey = HystrixThreadPoolKey.Factory.asKey(commandGroup.name());\n                    } else {\n                        nonNullThreadPoolKey = threadPoolKey;\n                    }\n                    HystrixCommandMetrics newCommandMetrics = new HystrixCommandMetrics(key, commandGroup, nonNullThreadPoolKey, properties, HystrixPlugins.getInstance().getEventNotifier());\n                    metrics.putIfAbsent(key.name(), newCommandMetrics);\n                    return newCommandMetrics;\n                }\n            }\n        }\n    }\n\n    /**\n     * Get the {@link HystrixCommandMetrics} instance for a given {@link HystrixCommandKey} or null if one does not exist.\n     * \n     * @param key\n     *            {@link HystrixCommandKey} of {@link HystrixCommand} instance requesting the {@link HystrixCommandMetrics}\n     * @return {@link HystrixCommandMetrics}\n     */\n    public static HystrixCommandMetrics getInstance(HystrixCommandKey key) {\n        return metrics.get(key.name());\n    }\n\n    /**\n     * All registered instances of {@link HystrixCommandMetrics}\n     * \n     * @return {@code Collection<HystrixCommandMetrics>}\n     */\n    public static Collection<HystrixCommandMetrics> getInstances() {\n        return Collections.unmodifiableCollection(metrics.values());\n    }\n\n    /**\n     * Clears all state from metrics. If new requests come in instances will be recreated and metrics started from scratch.\n     */\n    /* package */ static void reset() {\n        for (HystrixCommandMetrics metricsInstance: getInstances()) {\n            metricsInstance.unsubscribeAll();\n        }\n        metrics.clear();\n    }\n\n    private final HystrixCommandProperties properties;\n    private final HystrixCommandKey key;\n    private final HystrixCommandGroupKey group;\n    private final HystrixThreadPoolKey threadPoolKey;\n    private final AtomicInteger concurrentExecutionCount = new AtomicInteger();\n\n    private HealthCountsStream healthCountsStream;\n    private final RollingCommandEventCounterStream rollingCommandEventCounterStream;\n    private final CumulativeCommandEventCounterStream cumulativeCommandEventCounterStream;\n    private final RollingCommandLatencyDistributionStream rollingCommandLatencyDistributionStream;\n    private final RollingCommandUserLatencyDistributionStream rollingCommandUserLatencyDistributionStream;\n    private final RollingCommandMaxConcurrencyStream rollingCommandMaxConcurrencyStream;\n\n    /* package */HystrixCommandMetrics(final HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixThreadPoolKey threadPoolKey, HystrixCommandProperties properties, HystrixEventNotifier eventNotifier) {\n        super(null);\n        this.key = key;\n        this.group = commandGroup;\n        this.threadPoolKey = threadPoolKey;\n        this.properties = properties;\n\n        healthCountsStream = HealthCountsStream.getInstance(key, properties);\n        rollingCommandEventCounterStream = RollingCommandEventCounterStream.getInstance(key, properties);\n        cumulativeCommandEventCounterStream = CumulativeCommandEventCounterStream.getInstance(key, properties);\n\n        rollingCommandLatencyDistributionStream = RollingCommandLatencyDistributionStream.getInstance(key, properties);\n        rollingCommandUserLatencyDistributionStream = RollingCommandUserLatencyDistributionStream.getInstance(key, properties);\n        rollingCommandMaxConcurrencyStream = RollingCommandMaxConcurrencyStream.getInstance(key, properties);\n    }\n\n    /* package */ synchronized void resetStream() {\n        healthCountsStream.unsubscribe();\n        HealthCountsStream.removeByKey(key);\n        healthCountsStream = HealthCountsStream.getInstance(key, properties);\n    }\n\n    /**\n     * {@link HystrixCommandKey} these metrics represent.\n     * \n     * @return HystrixCommandKey\n     */\n    public HystrixCommandKey getCommandKey() {\n        return key;\n    }\n\n    /**\n     * {@link HystrixCommandGroupKey} of the {@link HystrixCommand} these metrics represent.\n     *\n     * @return HystrixCommandGroupKey\n     */\n    public HystrixCommandGroupKey getCommandGroup() {\n        return group;\n    }\n\n    /**\n     * {@link HystrixThreadPoolKey} used by {@link HystrixCommand} these metrics represent.\n     *\n     * @return HystrixThreadPoolKey\n     */\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    /**\n     * {@link HystrixCommandProperties} of the {@link HystrixCommand} these metrics represent.\n     * \n     * @return HystrixCommandProperties\n     */\n    public HystrixCommandProperties getProperties() {\n        return properties;\n    }\n\n    public long getRollingCount(HystrixEventType eventType) {\n        return rollingCommandEventCounterStream.getLatest(eventType);\n    }\n\n    public long getCumulativeCount(HystrixEventType eventType) {\n        return cumulativeCommandEventCounterStream.getLatest(eventType);\n    }\n\n    @Override\n    public long getCumulativeCount(HystrixRollingNumberEvent event) {\n        return getCumulativeCount(HystrixEventType.from(event));\n    }\n\n    @Override\n    public long getRollingCount(HystrixRollingNumberEvent event) {\n        return getRollingCount(HystrixEventType.from(event));\n    }\n\n    /**\n     * Retrieve the execution time (in milliseconds) for the {@link HystrixCommand#run()} method being invoked at a given percentile.\n     * <p>\n     * Percentile capture and calculation is configured via {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()} and other related properties.\n     * \n     * @param percentile\n     *            Percentile such as 50, 99, or 99.5.\n     * @return int time in milliseconds\n     */\n    public int getExecutionTimePercentile(double percentile) {\n        return rollingCommandLatencyDistributionStream.getLatestPercentile(percentile);\n    }\n\n    /**\n     * The mean (average) execution time (in milliseconds) for the {@link HystrixCommand#run()}.\n     * <p>\n     * This uses the same backing data as {@link #getExecutionTimePercentile};\n     * \n     * @return int time in milliseconds\n     */\n    public int getExecutionTimeMean() {\n        return rollingCommandLatencyDistributionStream.getLatestMean();\n    }\n\n    /**\n     * Retrieve the total end-to-end execution time (in milliseconds) for {@link HystrixCommand#execute()} or {@link HystrixCommand#queue()} at a given percentile.\n     * <p>\n     * When execution is successful this would include time from {@link #getExecutionTimePercentile} but when execution\n     * is being rejected, short-circuited, or timed-out then the time will differ.\n     * <p>\n     * This time can be lower than {@link #getExecutionTimePercentile} when a timeout occurs and the backing\n     * thread that calls {@link HystrixCommand#run()} is still running.\n     * <p>\n     * When rejections or short-circuits occur then {@link HystrixCommand#run()} will not be executed and thus\n     * not contribute time to {@link #getExecutionTimePercentile} but time will still show up in this metric for the end-to-end time.\n     * <p>\n     * This metric gives visibility into the total cost of {@link HystrixCommand} execution including\n     * the overhead of queuing, executing and waiting for a thread to invoke {@link HystrixCommand#run()} .\n     * <p>\n     * Percentile capture and calculation is configured via {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()} and other related properties.\n     * \n     * @param percentile\n     *            Percentile such as 50, 99, or 99.5.\n     * @return int time in milliseconds\n     */\n    public int getTotalTimePercentile(double percentile) {\n        return rollingCommandUserLatencyDistributionStream.getLatestPercentile(percentile);\n    }\n\n    /**\n     * The mean (average) execution time (in milliseconds) for {@link HystrixCommand#execute()} or {@link HystrixCommand#queue()}.\n     * <p>\n     * This uses the same backing data as {@link #getTotalTimePercentile};\n     * \n     * @return int time in milliseconds\n     */\n    public int getTotalTimeMean() {\n        return rollingCommandUserLatencyDistributionStream.getLatestMean();\n    }\n\n    public long getRollingMaxConcurrentExecutions() {\n        return rollingCommandMaxConcurrencyStream.getLatestRollingMax();\n    }\n\n    /**\n     * Current number of concurrent executions of {@link HystrixCommand#run()};\n     * \n     * @return int\n     */\n    public int getCurrentConcurrentExecutionCount() {\n        return concurrentExecutionCount.get();\n    }\n\n    /* package-private */ void markCommandStart(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey, HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy) {\n        int currentCount = concurrentExecutionCount.incrementAndGet();\n        HystrixThreadEventStream.getInstance().commandExecutionStarted(commandKey, threadPoolKey, isolationStrategy, currentCount);\n    }\n\n    /* package-private */ void markCommandDone(ExecutionResult executionResult, HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey, boolean executionStarted) {\n        HystrixThreadEventStream.getInstance().executionDone(executionResult, commandKey, threadPoolKey);\n        if (executionStarted) {\n            concurrentExecutionCount.decrementAndGet();\n        }\n    }\n\n    /* package-private */ HealthCountsStream getHealthCountsStream() {\n        return healthCountsStream;\n    }\n\n    /**\n     * Retrieve a snapshot of total requests, error count and error percentage.\n     *\n     * This metrics should measure the actual health of a {@link HystrixCommand}.  For that reason, the following are included:\n     * <p><ul>\n     * <li>{@link HystrixEventType#SUCCESS}\n     * <li>{@link HystrixEventType#FAILURE}\n     * <li>{@link HystrixEventType#TIMEOUT}\n     * <li>{@link HystrixEventType#THREAD_POOL_REJECTED}\n     * <li>{@link HystrixEventType#SEMAPHORE_REJECTED}\n     * </ul><p>\n     * The following are not included in either attempts/failures:\n     * <p><ul>\n     * <li>{@link HystrixEventType#BAD_REQUEST} - this event denotes bad arguments to the command and not a problem with the command\n     * <li>{@link HystrixEventType#SHORT_CIRCUITED} - this event measures a health problem in the past, not a problem with the current state\n     * <li>{@link HystrixEventType#CANCELLED} - this event denotes a user-cancelled command.  It's not known if it would have been a success or failure, so it shouldn't count for either\n     * <li>All Fallback metrics\n     * <li>{@link HystrixEventType#EMIT} - this event is not a terminal state for the command\n     * <li>{@link HystrixEventType#COLLAPSED} - this event is about the batching process, not the command execution\n     * </ul><p>\n     * \n     * @return {@link HealthCounts}\n     */\n    public HealthCounts getHealthCounts() {\n        return healthCountsStream.getLatest();\n    }\n\n    private void unsubscribeAll() {\n        healthCountsStream.unsubscribe();\n        rollingCommandEventCounterStream.unsubscribe();\n        cumulativeCommandEventCounterStream.unsubscribe();\n        rollingCommandLatencyDistributionStream.unsubscribe();\n        rollingCommandUserLatencyDistributionStream.unsubscribe();\n        rollingCommandMaxConcurrencyStream.unsubscribe();\n    }\n\n    /**\n     * Number of requests during rolling window.\n     * Number that failed (failure + success + timeout + threadPoolRejected + semaphoreRejected).\n     * Error percentage;\n     */\n    public static class HealthCounts {\n        private final long totalCount;\n        private final long errorCount;\n        private final int errorPercentage;\n\n        HealthCounts(long total, long error) {\n            this.totalCount = total;\n            this.errorCount = error;\n            if (totalCount > 0) {\n                this.errorPercentage = (int) ((double) errorCount / totalCount * 100);\n            } else {\n                this.errorPercentage = 0;\n            }\n        }\n\n        private static final HealthCounts EMPTY = new HealthCounts(0, 0);\n\n        public long getTotalRequests() {\n            return totalCount;\n        }\n\n        public long getErrorCount() {\n            return errorCount;\n        }\n\n        public int getErrorPercentage() {\n            return errorPercentage;\n        }\n\n        public HealthCounts plus(long[] eventTypeCounts) {\n            long updatedTotalCount = totalCount;\n            long updatedErrorCount = errorCount;\n\n            long successCount = eventTypeCounts[HystrixEventType.SUCCESS.ordinal()];\n            long failureCount = eventTypeCounts[HystrixEventType.FAILURE.ordinal()];\n            long timeoutCount = eventTypeCounts[HystrixEventType.TIMEOUT.ordinal()];\n            long threadPoolRejectedCount = eventTypeCounts[HystrixEventType.THREAD_POOL_REJECTED.ordinal()];\n            long semaphoreRejectedCount = eventTypeCounts[HystrixEventType.SEMAPHORE_REJECTED.ordinal()];\n\n            updatedTotalCount += (successCount + failureCount + timeoutCount + threadPoolRejectedCount + semaphoreRejectedCount);\n            updatedErrorCount += (failureCount + timeoutCount + threadPoolRejectedCount + semaphoreRejectedCount);\n            return new HealthCounts(updatedTotalCount, updatedErrorCount);\n        }\n\n        public static HealthCounts empty() {\n            return EMPTY;\n        }\n\n        public String toString() {\n            return \"HealthCounts[\" + errorCount + \" / \" + totalCount + \" : \" + getErrorPercentage() + \"%]\";\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandProperties.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean;\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forString;\n\nimport java.util.concurrent.Future;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixRollingNumber;\nimport com.netflix.hystrix.util.HystrixRollingPercentile;\n\n/**\n * Properties for instances of {@link HystrixCommand}.\n * <p>\n * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)\n */\npublic abstract class HystrixCommandProperties {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixCommandProperties.class);\n\n    /* defaults */\n    /* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)\n    private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second\n    private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter\n    private static final Integer default_circuitBreakerSleepWindowInMilliseconds = 5000;// default => sleepWindow: 5000 = 5 seconds that we will sleep before trying again after tripping the circuit\n    private static final Integer default_circuitBreakerErrorThresholdPercentage = 50;// default => errorThresholdPercentage = 50 = if 50%+ of requests in 10 seconds are failures or latent then we will trip the circuit\n    private static final Boolean default_circuitBreakerForceOpen = false;// default => forceCircuitOpen = false (we want to allow traffic)\n    /* package */ static final Boolean default_circuitBreakerForceClosed = false;// default => ignoreErrors = false \n    private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second\n    private static final Boolean default_executionTimeoutEnabled = true;\n    private static final ExecutionIsolationStrategy default_executionIsolationStrategy = ExecutionIsolationStrategy.THREAD;\n    private static final Boolean default_executionIsolationThreadInterruptOnTimeout = true;\n    private static final Boolean default_executionIsolationThreadInterruptOnFutureCancel = false;\n    private static final Boolean default_metricsRollingPercentileEnabled = true;\n    private static final Boolean default_requestCacheEnabled = true;\n    private static final Integer default_fallbackIsolationSemaphoreMaxConcurrentRequests = 10;\n    private static final Boolean default_fallbackEnabled = true;\n    private static final Integer default_executionIsolationSemaphoreMaxConcurrentRequests = 10;\n    private static final Boolean default_requestLogEnabled = true;\n    private static final Boolean default_circuitBreakerEnabled = true;\n    private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile \n    private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)\n    private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket\n    private static final Integer default_metricsHealthSnapshotIntervalInMilliseconds = 500; // default to 500ms as max frequency between allowing snapshots of health (error percentage etc)\n\n    @SuppressWarnings(\"unused\") private final HystrixCommandKey key;\n    private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold; // number of requests that must be made within a statisticalWindow before open/close decisions are made using stats\n    private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds; // milliseconds after tripping circuit before allowing retry\n    private final HystrixProperty<Boolean> circuitBreakerEnabled; // Whether circuit breaker should be enabled.\n    private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage; // % of 'marks' that must be failed to trip the circuit\n    private final HystrixProperty<Boolean> circuitBreakerForceOpen; // a property to allow forcing the circuit open (stopping all requests)\n    private final HystrixProperty<Boolean> circuitBreakerForceClosed; // a property to allow ignoring errors and therefore never trip 'open' (ie. allow all traffic through)\n    private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy; // Whether a command should be executed in a separate thread or not.\n    private final HystrixProperty<Integer> executionTimeoutInMilliseconds; // Timeout value in milliseconds for a command\n    private final HystrixProperty<Boolean> executionTimeoutEnabled; //Whether timeout should be triggered\n    private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride; // What thread-pool this command should run in (if running on a separate thread).\n    private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests; // Number of permits for execution semaphore\n    private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests; // Number of permits for fallback semaphore\n    private final HystrixProperty<Boolean> fallbackEnabled; // Whether fallback should be attempted.\n    private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout; // Whether an underlying Future/Thread (when runInSeparateThread == true) should be interrupted after a timeout\n    private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnFutureCancel; // Whether canceling an underlying Future/Thread (when runInSeparateThread == true) should interrupt the execution thread\n    private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds; // milliseconds back that will be tracked\n    private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow\n    private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; // Whether monitoring should be enabled (SLA and Tracers).\n    private final HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds; // number of milliseconds that will be tracked in RollingPercentile\n    private final HystrixProperty<Integer> metricsRollingPercentileWindowBuckets; // number of buckets percentileWindow will be divided into\n    private final HystrixProperty<Integer> metricsRollingPercentileBucketSize; // how many values will be stored in each percentileWindowBucket\n    private final HystrixProperty<Integer> metricsHealthSnapshotIntervalInMilliseconds; // time between health snapshots\n    private final HystrixProperty<Boolean> requestLogEnabled; // whether command request logging is enabled.\n    private final HystrixProperty<Boolean> requestCacheEnabled; // Whether request caching is enabled.\n\n    /**\n     * Isolation strategy to use when executing a {@link HystrixCommand}.\n     * <p>\n     * <ul>\n     * <li>THREAD: Execute the {@link HystrixCommand#run()} method on a separate thread and restrict concurrent executions using the thread-pool size.</li>\n     * <li>SEMAPHORE: Execute the {@link HystrixCommand#run()} method on the calling thread and restrict concurrent executions using the semaphore permit count.</li>\n     * </ul>\n     */\n    public static enum ExecutionIsolationStrategy {\n        THREAD, SEMAPHORE\n    }\n\n    protected HystrixCommandProperties(HystrixCommandKey key) {\n        this(key, new Setter(), \"hystrix\");\n    }\n\n    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder) {\n        this(key, builder, \"hystrix\");\n    }\n\n    // known that we're using deprecated HystrixPropertiesChainedServoProperty until ChainedDynamicProperty exists in Archaius\n    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {\n        this.key = key;\n        this.circuitBreakerEnabled = getProperty(propertyPrefix, key, \"circuitBreaker.enabled\", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);\n        this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, \"circuitBreaker.requestVolumeThreshold\", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);\n        this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, \"circuitBreaker.sleepWindowInMilliseconds\", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);\n        this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, \"circuitBreaker.errorThresholdPercentage\", builder.getCircuitBreakerErrorThresholdPercentage(), default_circuitBreakerErrorThresholdPercentage);\n        this.circuitBreakerForceOpen = getProperty(propertyPrefix, key, \"circuitBreaker.forceOpen\", builder.getCircuitBreakerForceOpen(), default_circuitBreakerForceOpen);\n        this.circuitBreakerForceClosed = getProperty(propertyPrefix, key, \"circuitBreaker.forceClosed\", builder.getCircuitBreakerForceClosed(), default_circuitBreakerForceClosed);\n        this.executionIsolationStrategy = getProperty(propertyPrefix, key, \"execution.isolation.strategy\", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);\n        //this property name is now misleading.  //TODO figure out a good way to deprecate this property name\n        this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, \"execution.isolation.thread.timeoutInMilliseconds\", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);\n        this.executionTimeoutEnabled = getProperty(propertyPrefix, key, \"execution.timeout.enabled\", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);\n        this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, key, \"execution.isolation.thread.interruptOnTimeout\", builder.getExecutionIsolationThreadInterruptOnTimeout(), default_executionIsolationThreadInterruptOnTimeout);\n        this.executionIsolationThreadInterruptOnFutureCancel = getProperty(propertyPrefix, key, \"execution.isolation.thread.interruptOnFutureCancel\", builder.getExecutionIsolationThreadInterruptOnFutureCancel(), default_executionIsolationThreadInterruptOnFutureCancel);\n        this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, \"execution.isolation.semaphore.maxConcurrentRequests\", builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), default_executionIsolationSemaphoreMaxConcurrentRequests);\n        this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, \"fallback.isolation.semaphore.maxConcurrentRequests\", builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), default_fallbackIsolationSemaphoreMaxConcurrentRequests);\n        this.fallbackEnabled = getProperty(propertyPrefix, key, \"fallback.enabled\", builder.getFallbackEnabled(), default_fallbackEnabled);\n        this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, \"metrics.rollingStats.timeInMilliseconds\", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);\n        this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, \"metrics.rollingStats.numBuckets\", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);\n        this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.enabled\", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);\n        this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.timeInMilliseconds\", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);\n        this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.numBuckets\", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);\n        this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, \"metrics.rollingPercentile.bucketSize\", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);\n        this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, key, \"metrics.healthSnapshot.intervalInMilliseconds\", builder.getMetricsHealthSnapshotIntervalInMilliseconds(), default_metricsHealthSnapshotIntervalInMilliseconds);\n        this.requestCacheEnabled = getProperty(propertyPrefix, key, \"requestCache.enabled\", builder.getRequestCacheEnabled(), default_requestCacheEnabled);\n        this.requestLogEnabled = getProperty(propertyPrefix, key, \"requestLog.enabled\", builder.getRequestLogEnabled(), default_requestLogEnabled);\n\n        // threadpool doesn't have a global override, only instance level makes sense\n        this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + \".command.\" + key.name() + \".threadPoolKeyOverride\", null).build();\n    }\n\n    /**\n     * Whether to use a {@link HystrixCircuitBreaker} or not. If false no circuit-breaker logic will be used and all requests permitted.\n     * <p>\n     * This is similar in effect to {@link #circuitBreakerForceClosed()} except that continues tracking metrics and knowing whether it\n     * should be open/closed, this property results in not even instantiating a circuit-breaker.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> circuitBreakerEnabled() {\n        return circuitBreakerEnabled;\n    }\n\n    /**\n     * Error percentage threshold (as whole number such as 50) at which point the circuit breaker will trip open and reject requests.\n     * <p>\n     * It will stay tripped for the duration defined in {@link #circuitBreakerSleepWindowInMilliseconds()};\n     * <p>\n     * The error percentage this is compared against comes from {@link HystrixCommandMetrics#getHealthCounts()}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage() {\n        return circuitBreakerErrorThresholdPercentage;\n    }\n\n    /**\n     * If true the {@link HystrixCircuitBreaker#allowRequest()} will always return true to allow requests regardless of the error percentage from {@link HystrixCommandMetrics#getHealthCounts()}.\n     * <p>\n     * The {@link #circuitBreakerForceOpen()} property takes precedence so if it set to true this property does nothing.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> circuitBreakerForceClosed() {\n        return circuitBreakerForceClosed;\n    }\n\n    /**\n     * If true the {@link HystrixCircuitBreaker#allowRequest()} will always return false, causing the circuit to be open (tripped) and reject all requests.\n     * <p>\n     * This property takes precedence over {@link #circuitBreakerForceClosed()};\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> circuitBreakerForceOpen() {\n        return circuitBreakerForceOpen;\n    }\n\n    /**\n     * Minimum number of requests in the {@link #metricsRollingStatisticalWindowInMilliseconds()} that must exist before the {@link HystrixCircuitBreaker} will trip.\n     * <p>\n     * If below this number the circuit will not trip regardless of error percentage.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold() {\n        return circuitBreakerRequestVolumeThreshold;\n    }\n\n    /**\n     * The time in milliseconds after a {@link HystrixCircuitBreaker} trips open that it should wait before trying requests again.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds() {\n        return circuitBreakerSleepWindowInMilliseconds;\n    }\n\n    /**\n     * Number of concurrent requests permitted to {@link HystrixCommand#run()}. Requests beyond the concurrent limit will be rejected.\n     * <p>\n     * Applicable only when {@link #executionIsolationStrategy()} == SEMAPHORE.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests() {\n        return executionIsolationSemaphoreMaxConcurrentRequests;\n    }\n\n    /**\n     * What isolation strategy {@link HystrixCommand#run()} will be executed with.\n     * <p>\n     * If {@link ExecutionIsolationStrategy#THREAD} then it will be executed on a separate thread and concurrent requests limited by the number of threads in the thread-pool.\n     * <p>\n     * If {@link ExecutionIsolationStrategy#SEMAPHORE} then it will be executed on the calling thread and concurrent requests limited by the semaphore count.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy() {\n        return executionIsolationStrategy;\n    }\n\n    /**\n     * Whether the execution thread should attempt an interrupt (using {@link Future#cancel}) when a thread times out.\n     * <p>\n     * Applicable only when {@link #executionIsolationStrategy()} == THREAD.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout() {\n        return executionIsolationThreadInterruptOnTimeout;\n    }\n\n    /**\n     * Whether the execution thread should be interrupted if the execution observable is unsubscribed or the future is cancelled via {@link Future#cancel(true)}).\n     * <p>\n     * Applicable only when {@link #executionIsolationStrategy()} == THREAD.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> executionIsolationThreadInterruptOnFutureCancel() {\n        return executionIsolationThreadInterruptOnFutureCancel;\n    }\n\n    /**\n     * Allow a dynamic override of the {@link HystrixThreadPoolKey} that will dynamically change which {@link HystrixThreadPool} a {@link HystrixCommand} executes on.\n     * <p>\n     * Typically this should return NULL which will cause it to use the {@link HystrixThreadPoolKey} injected into a {@link HystrixCommand} or derived from the {@link HystrixCommandGroupKey}.\n     * <p>\n     * When set the injected or derived values will be ignored and a new {@link HystrixThreadPool} created (if necessary) and the {@link HystrixCommand} will begin using the newly defined pool.\n     * \n     * @return {@code HystrixProperty<String>}\n     */\n    public HystrixProperty<String> executionIsolationThreadPoolKeyOverride() {\n        return executionIsolationThreadPoolKeyOverride;\n    }\n\n    /**\n     *\n     * @deprecated  As of release 1.4.0, replaced by {@link #executionTimeoutInMilliseconds()}.  Timeout is no longer specific to thread-isolation commands, so the thread-specific name is misleading.\n     *\n     * Time in milliseconds at which point the command will timeout and halt execution.\n     * <p>\n     * If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted.\n     * If the command is semaphore-isolated and a {@link HystrixObservableCommand}, that command will get unsubscribed.\n     * <p>\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    @Deprecated //prefer {@link #executionTimeoutInMilliseconds}\n    public HystrixProperty<Integer> executionIsolationThreadTimeoutInMilliseconds() {\n        return executionTimeoutInMilliseconds;\n    }\n\n    /**\n     * Time in milliseconds at which point the command will timeout and halt execution.\n     * <p>\n     * If {@link #executionIsolationThreadInterruptOnTimeout} == true and the command is thread-isolated, the executing thread will be interrupted.\n     * If the command is semaphore-isolated and a {@link HystrixObservableCommand}, that command will get unsubscribed.\n     * <p>\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> executionTimeoutInMilliseconds() {\n        /**\n         * Calling a deprecated method here is a temporary workaround.  We do this because {@link #executionTimeoutInMilliseconds()} is a new method (as of 1.4.0-rc.7) and an extending\n         * class will not have this method.  It will have {@link #executionIsolationThreadTimeoutInMilliseconds()}, however.\n         * So, to stay compatible with an extension, we perform this redirect.\n         */\n        return executionIsolationThreadTimeoutInMilliseconds();\n    }\n\n    /**\n     * Whether the timeout mechanism is enabled for this command\n     *\n     * @return {@code HystrixProperty<Boolean>}\n     *\n     * @since 1.4.4\n     */\n    public HystrixProperty<Boolean> executionTimeoutEnabled() {\n        return executionTimeoutEnabled;\n    }\n\n    /**\n     * Number of concurrent requests permitted to {@link HystrixCommand#getFallback()}. Requests beyond the concurrent limit will fail-fast and not attempt retrieving a fallback.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests() {\n        return fallbackIsolationSemaphoreMaxConcurrentRequests;\n    }\n\n    /**\n     * Whether {@link HystrixCommand#getFallback()} should be attempted when failure occurs.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     * \n     * @since 1.2\n     */\n    public HystrixProperty<Boolean> fallbackEnabled() {\n        return fallbackEnabled;\n    }\n\n    /**\n     * Time in milliseconds to wait between allowing health snapshots to be taken that calculate success and error percentages and affect {@link HystrixCircuitBreaker#isOpen()} status.\n     * <p>\n     * On high-volume circuits the continual calculation of error percentage can become CPU intensive thus this controls how often it is calculated.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsHealthSnapshotIntervalInMilliseconds() {\n        return metricsHealthSnapshotIntervalInMilliseconds;\n    }\n\n    /**\n     * Maximum number of values stored in each bucket of the rolling percentile. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileBucketSize() {\n        return metricsRollingPercentileBucketSize;\n    }\n\n    /**\n     * Whether percentile metrics should be captured using {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> metricsRollingPercentileEnabled() {\n        return metricsRollingPercentileEnabled;\n    }\n\n    /**\n     * Duration of percentile rolling window in milliseconds. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     * @deprecated Use {@link #metricsRollingPercentileWindowInMilliseconds()}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileWindow() {\n        return metricsRollingPercentileWindowInMilliseconds;\n    }\n\n    /**\n     * Duration of percentile rolling window in milliseconds. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds() {\n        return metricsRollingPercentileWindowInMilliseconds;\n    }\n\n    /**\n     * Number of buckets the rolling percentile window is broken into. This is passed into {@link HystrixRollingPercentile} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingPercentileWindowBuckets() {\n        return metricsRollingPercentileWindowBuckets;\n    }\n\n    /**\n     * Duration of statistical rolling window in milliseconds. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds() {\n        return metricsRollingStatisticalWindowInMilliseconds;\n    }\n\n    /**\n     * Number of buckets the rolling statistical window is broken into. This is passed into {@link HystrixRollingNumber} inside {@link HystrixCommandMetrics}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets() {\n        return metricsRollingStatisticalWindowBuckets;\n    }\n\n    /**\n     * Whether {@link HystrixCommand#getCacheKey()} should be used with {@link HystrixRequestCache} to provide de-duplication functionality via request-scoped caching.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> requestCacheEnabled() {\n        return requestCacheEnabled;\n    }\n\n    /**\n     * Whether {@link HystrixCommand} execution and events should be logged to {@link HystrixRequestLog}.\n     * \n     * @return {@code HystrixProperty<Boolean>}\n     */\n    public HystrixProperty<Boolean> requestLogEnabled() {\n        return requestLogEnabled;\n    }\n\n    private static HystrixProperty<Boolean> getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) {\n        return forBoolean()\n                .add(propertyPrefix + \".command.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".command.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    private static HystrixProperty<Integer> getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, Integer builderOverrideValue, Integer defaultValue) {\n        return forInteger()\n                .add(propertyPrefix + \".command.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".command.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private static HystrixProperty<String> getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, String builderOverrideValue, String defaultValue) {\n        return forString()\n                .add(propertyPrefix + \".command.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".command.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    private static HystrixProperty<ExecutionIsolationStrategy> getProperty(final String propertyPrefix, final HystrixCommandKey key, final String instanceProperty, final ExecutionIsolationStrategy builderOverrideValue, final ExecutionIsolationStrategy defaultValue) {\n        return new ExecutionIsolationStrategyHystrixProperty(builderOverrideValue, key, propertyPrefix, defaultValue, instanceProperty);\n\n    }\n\n    /**\n     * HystrixProperty that converts a String to ExecutionIsolationStrategy so we remain TypeSafe.\n     */\n    private static final class ExecutionIsolationStrategyHystrixProperty implements HystrixProperty<ExecutionIsolationStrategy> {\n        private final HystrixDynamicProperty<String> property;\n        private volatile ExecutionIsolationStrategy value;\n        private final ExecutionIsolationStrategy defaultValue;\n\n        private ExecutionIsolationStrategyHystrixProperty(ExecutionIsolationStrategy builderOverrideValue, HystrixCommandKey key, String propertyPrefix, ExecutionIsolationStrategy defaultValue, String instanceProperty) {\n            this.defaultValue = defaultValue;\n            String overrideValue = null;\n            if (builderOverrideValue != null) {\n                overrideValue = builderOverrideValue.name();\n            }\n            property = forString()\n                    .add(propertyPrefix + \".command.\" + key.name() + \".\" + instanceProperty, overrideValue)\n                    .add(propertyPrefix + \".command.default.\" + instanceProperty, defaultValue.name())\n                    .build();\n\n            // initialize the enum value from the property\n            parseProperty();\n\n            // use a callback to handle changes so we only handle the parse cost on updates rather than every fetch\n            property.addCallback(new Runnable() {\n\n                @Override\n                public void run() {\n                    // when the property value changes we'll update the value\n                    parseProperty();\n                }\n\n            });\n        }\n\n        @Override\n        public ExecutionIsolationStrategy get() {\n            return value;\n        }\n\n        private void parseProperty() {\n            try {\n                value = ExecutionIsolationStrategy.valueOf(property.get());\n            } catch (Exception e) {\n                logger.error(\"Unable to derive ExecutionIsolationStrategy from property value: \" + property.get(), e);\n                // use the default value\n                value = defaultValue;\n            }\n        }\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     */\n    public static Setter Setter() {\n        return new Setter();\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     * Groovy has a bug (GROOVY-6286) which does not allow method names and inner classes to have the same name\n     * This method fixes Issue #967 and allows Groovy consumers to choose this method and not trigger the bug\n     */\n    public static Setter defaultSetter() {\n        return Setter();\n    }\n\n    /**\n     * Fluent interface that allows chained setting of properties that can be passed into a {@link HystrixCommand} constructor to inject instance specific property overrides.\n     * <p>\n     * See {@link HystrixPropertiesStrategy} for more information on order of precedence.\n     * <p>\n     * Example:\n     * <p>\n     * <pre> {@code\n     * HystrixCommandProperties.Setter()\n     *           .withExecutionTimeoutInMilliseconds(100)\n     *           .withExecuteCommandOnSeparateThread(true);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    public static class Setter {\n\n        private Boolean circuitBreakerEnabled = null;\n        private Integer circuitBreakerErrorThresholdPercentage = null;\n        private Boolean circuitBreakerForceClosed = null;\n        private Boolean circuitBreakerForceOpen = null;\n        private Integer circuitBreakerRequestVolumeThreshold = null;\n        private Integer circuitBreakerSleepWindowInMilliseconds = null;\n        private Integer executionIsolationSemaphoreMaxConcurrentRequests = null;\n        private ExecutionIsolationStrategy executionIsolationStrategy = null;\n        private Boolean executionIsolationThreadInterruptOnTimeout = null;\n        private Boolean executionIsolationThreadInterruptOnFutureCancel = null;\n        private Integer executionTimeoutInMilliseconds = null;\n        private Boolean executionTimeoutEnabled = null;\n        private Integer fallbackIsolationSemaphoreMaxConcurrentRequests = null;\n        private Boolean fallbackEnabled = null;\n        private Integer metricsHealthSnapshotIntervalInMilliseconds = null;\n        private Integer metricsRollingPercentileBucketSize = null;\n        private Boolean metricsRollingPercentileEnabled = null;\n        private Integer metricsRollingPercentileWindowInMilliseconds = null;\n        private Integer metricsRollingPercentileWindowBuckets = null;\n        /* null means it hasn't been overridden */\n        private Integer metricsRollingStatisticalWindowInMilliseconds = null;\n        private Integer metricsRollingStatisticalWindowBuckets = null;\n        private Boolean requestCacheEnabled = null;\n        private Boolean requestLogEnabled = null;\n\n        /* package */ Setter() {\n        }\n\n        public Boolean getCircuitBreakerEnabled() {\n            return circuitBreakerEnabled;\n        }\n\n        public Integer getCircuitBreakerErrorThresholdPercentage() {\n            return circuitBreakerErrorThresholdPercentage;\n        }\n\n        public Boolean getCircuitBreakerForceClosed() {\n            return circuitBreakerForceClosed;\n        }\n\n        public Boolean getCircuitBreakerForceOpen() {\n            return circuitBreakerForceOpen;\n        }\n\n        public Integer getCircuitBreakerRequestVolumeThreshold() {\n            return circuitBreakerRequestVolumeThreshold;\n        }\n\n        public Integer getCircuitBreakerSleepWindowInMilliseconds() {\n            return circuitBreakerSleepWindowInMilliseconds;\n        }\n\n        public Integer getExecutionIsolationSemaphoreMaxConcurrentRequests() {\n            return executionIsolationSemaphoreMaxConcurrentRequests;\n        }\n\n        public ExecutionIsolationStrategy getExecutionIsolationStrategy() {\n            return executionIsolationStrategy;\n        }\n\n        public Boolean getExecutionIsolationThreadInterruptOnTimeout() {\n            return executionIsolationThreadInterruptOnTimeout;\n        }\n\n        public Boolean getExecutionIsolationThreadInterruptOnFutureCancel() {\n\t\t\treturn executionIsolationThreadInterruptOnFutureCancel;\n\t\t}\n\n\t\t/**\n         * @deprecated As of 1.4.0, use {@link #getExecutionTimeoutInMilliseconds()}\n         */\n        @Deprecated\n        public Integer getExecutionIsolationThreadTimeoutInMilliseconds() {\n            return executionTimeoutInMilliseconds;\n        }\n\n        public Integer getExecutionTimeoutInMilliseconds() {\n            return executionTimeoutInMilliseconds;\n        }\n\n        public Boolean getExecutionTimeoutEnabled() {\n            return executionTimeoutEnabled;\n        }\n\n        public Integer getFallbackIsolationSemaphoreMaxConcurrentRequests() {\n            return fallbackIsolationSemaphoreMaxConcurrentRequests;\n        }\n\n        public Boolean getFallbackEnabled() {\n            return fallbackEnabled;\n        }\n\n        public Integer getMetricsHealthSnapshotIntervalInMilliseconds() {\n            return metricsHealthSnapshotIntervalInMilliseconds;\n        }\n\n        public Integer getMetricsRollingPercentileBucketSize() {\n            return metricsRollingPercentileBucketSize;\n        }\n\n        public Boolean getMetricsRollingPercentileEnabled() {\n            return metricsRollingPercentileEnabled;\n        }\n\n        public Integer getMetricsRollingPercentileWindowInMilliseconds() {\n            return metricsRollingPercentileWindowInMilliseconds;\n        }\n\n        public Integer getMetricsRollingPercentileWindowBuckets() {\n            return metricsRollingPercentileWindowBuckets;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowInMilliseconds() {\n            return metricsRollingStatisticalWindowInMilliseconds;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowBuckets() {\n            return metricsRollingStatisticalWindowBuckets;\n        }\n\n        public Boolean getRequestCacheEnabled() {\n            return requestCacheEnabled;\n        }\n\n        public Boolean getRequestLogEnabled() {\n            return requestLogEnabled;\n        }\n\n        public Setter withCircuitBreakerEnabled(boolean value) {\n            this.circuitBreakerEnabled = value;\n            return this;\n        }\n\n        public Setter withCircuitBreakerErrorThresholdPercentage(int value) {\n            this.circuitBreakerErrorThresholdPercentage = value;\n            return this;\n        }\n\n        public Setter withCircuitBreakerForceClosed(boolean value) {\n            this.circuitBreakerForceClosed = value;\n            return this;\n        }\n\n        public Setter withCircuitBreakerForceOpen(boolean value) {\n            this.circuitBreakerForceOpen = value;\n            return this;\n        }\n\n        public Setter withCircuitBreakerRequestVolumeThreshold(int value) {\n            this.circuitBreakerRequestVolumeThreshold = value;\n            return this;\n        }\n\n        public Setter withCircuitBreakerSleepWindowInMilliseconds(int value) {\n            this.circuitBreakerSleepWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withExecutionIsolationSemaphoreMaxConcurrentRequests(int value) {\n            this.executionIsolationSemaphoreMaxConcurrentRequests = value;\n            return this;\n        }\n\n        public Setter withExecutionIsolationStrategy(ExecutionIsolationStrategy value) {\n            this.executionIsolationStrategy = value;\n            return this;\n        }\n\n        public Setter withExecutionIsolationThreadInterruptOnTimeout(boolean value) {\n            this.executionIsolationThreadInterruptOnTimeout = value;\n            return this;\n        }\n\n        public Setter withExecutionIsolationThreadInterruptOnFutureCancel(boolean value) {\n            this.executionIsolationThreadInterruptOnFutureCancel = value;\n            return this;\n        }\n\n        /**\n         * @deprecated As of 1.4.0, replaced with {@link #withExecutionTimeoutInMilliseconds(int)}.  Timeouts are no longer applied only to thread-isolated commands, so a thread-specific name is misleading\n         */\n        @Deprecated\n        public Setter withExecutionIsolationThreadTimeoutInMilliseconds(int value) {\n            this.executionTimeoutInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withExecutionTimeoutInMilliseconds(int value) {\n            this.executionTimeoutInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withExecutionTimeoutEnabled(boolean value) {\n            this.executionTimeoutEnabled = value;\n            return this;\n        }\n\n        public Setter withFallbackIsolationSemaphoreMaxConcurrentRequests(int value) {\n            this.fallbackIsolationSemaphoreMaxConcurrentRequests = value;\n            return this;\n        }\n\n        public Setter withFallbackEnabled(boolean value) {\n            this.fallbackEnabled = value;\n            return this;\n        }\n\n        public Setter withMetricsHealthSnapshotIntervalInMilliseconds(int value) {\n            this.metricsHealthSnapshotIntervalInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileBucketSize(int value) {\n            this.metricsRollingPercentileBucketSize = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileEnabled(boolean value) {\n            this.metricsRollingPercentileEnabled = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileWindowInMilliseconds(int value) {\n            this.metricsRollingPercentileWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingPercentileWindowBuckets(int value) {\n            this.metricsRollingPercentileWindowBuckets = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowInMilliseconds(int value) {\n            this.metricsRollingStatisticalWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowBuckets(int value) {\n            this.metricsRollingStatisticalWindowBuckets = value;\n            return this;\n        }\n\n        public Setter withRequestCacheEnabled(boolean value) {\n            this.requestCacheEnabled = value;\n            return this;\n        }\n\n        public Setter withRequestLogEnabled(boolean value) {\n            this.requestLogEnabled = value;\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandResponseFromCache.java",
    "content": "package com.netflix.hystrix;\n\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class HystrixCommandResponseFromCache<R> extends HystrixCachedObservable<R> {\n    private final AbstractCommand<R> originalCommand;\n\n    /* package-private */ HystrixCommandResponseFromCache(Observable<R> originalObservable, final AbstractCommand<R> originalCommand) {\n        super(originalObservable);\n        this.originalCommand = originalCommand;\n    }\n\n    public Observable<R> toObservableWithStateCopiedInto(final AbstractCommand<R> commandToCopyStateInto) {\n        final AtomicBoolean completionLogicRun = new AtomicBoolean(false);\n\n        return cachedObservable\n                .doOnError(new Action1<Throwable>() {\n                    @Override\n                    public void call(Throwable throwable) {\n                        if (completionLogicRun.compareAndSet(false, true)) {\n                            commandCompleted(commandToCopyStateInto);\n                        }\n                    }\n                })\n                .doOnCompleted(new Action0() {\n                    @Override\n                    public void call() {\n                        if (completionLogicRun.compareAndSet(false, true)) {\n                            commandCompleted(commandToCopyStateInto);\n                        }\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        if (completionLogicRun.compareAndSet(false, true)) {\n                            commandUnsubscribed(commandToCopyStateInto);\n                        }\n                    }\n                });\n    }\n\n    private void commandCompleted(final AbstractCommand<R> commandToCopyStateInto) {\n        commandToCopyStateInto.executionResult = originalCommand.executionResult;\n    }\n\n    private void commandUnsubscribed(final AbstractCommand<R> commandToCopyStateInto) {\n        commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.addEvent(HystrixEventType.CANCELLED);\n        commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.setExecutionLatency(-1);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixCounters.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Class with global statistics on Hystrix runtime behavior.\n * All of the data available via this class is static and scoped at the JVM level\n */\npublic class HystrixCounters {\n    private static final AtomicInteger concurrentThreadsExecuting = new AtomicInteger(0);\n\n    /* package-private */ static int incrementGlobalConcurrentThreads() {\n        return concurrentThreadsExecuting.incrementAndGet();\n    }\n\n    /* package-private */ static int decrementGlobalConcurrentThreads() {\n        return concurrentThreadsExecuting.decrementAndGet();\n    }\n\n    /**\n     * Return the number of currently-executing Hystrix threads\n     * @return number of currently-executing Hystrix threads\n     */\n    public static int getGlobalConcurrentThreadsExecuting() {\n        return concurrentThreadsExecuting.get();\n    }\n\n    /**\n     * Return the number of unique {@link HystrixCommand}s that have been registered\n     * @return number of unique {@link HystrixCommand}s that have been registered\n     */\n    public static int getCommandCount() {\n        return HystrixCommandKey.Factory.getCommandCount();\n    }\n\n    /**\n     * Return the number of unique {@link HystrixThreadPool}s that have been registered\n     * @return number of unique {@link HystrixThreadPool}s that have been registered\n     */\n    public static int getThreadPoolCount() {\n        return HystrixThreadPoolKey.Factory.getThreadPoolCount();\n    }\n\n    /**\n     * Return the number of unique {@link HystrixCommandGroupKey}s that have been registered\n     * @return number of unique {@link HystrixCommandGroupKey}s that have been registered\n     */\n    public static int getGroupCount() {\n        return HystrixCommandGroupKey.Factory.getGroupCount();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixEventType.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Various states/events that execution can result in or have tracked.\n * <p>\n * These are most often accessed via {@link HystrixRequestLog} or {@link HystrixCommand#getExecutionEvents()}.\n */\npublic enum HystrixEventType {\n    EMIT(false),\n    SUCCESS(true),\n    FAILURE(false),\n    TIMEOUT(false),\n    BAD_REQUEST(true),\n    SHORT_CIRCUITED(false),\n    THREAD_POOL_REJECTED(false),\n    SEMAPHORE_REJECTED(false),\n    FALLBACK_EMIT(false),\n    FALLBACK_SUCCESS(true),\n    FALLBACK_FAILURE(true),\n    FALLBACK_REJECTION(true),\n    FALLBACK_DISABLED(true),\n    FALLBACK_MISSING(true),\n    EXCEPTION_THROWN(false),\n    RESPONSE_FROM_CACHE(true),\n    CANCELLED(true),\n    COLLAPSED(false),\n    COMMAND_MAX_ACTIVE(false);\n\n    private final boolean isTerminal;\n\n    HystrixEventType(boolean isTerminal) {\n        this.isTerminal = isTerminal;\n    }\n\n    public boolean isTerminal() {\n        return isTerminal;\n    }\n\n    public static HystrixEventType from(HystrixRollingNumberEvent event) {\n        switch (event) {\n            case EMIT: return EMIT;\n            case SUCCESS: return SUCCESS;\n            case FAILURE: return FAILURE;\n            case TIMEOUT: return TIMEOUT;\n            case SHORT_CIRCUITED: return SHORT_CIRCUITED;\n            case THREAD_POOL_REJECTED: return THREAD_POOL_REJECTED;\n            case SEMAPHORE_REJECTED: return SEMAPHORE_REJECTED;\n            case FALLBACK_EMIT: return FALLBACK_EMIT;\n            case FALLBACK_SUCCESS: return FALLBACK_SUCCESS;\n            case FALLBACK_FAILURE: return FALLBACK_FAILURE;\n            case FALLBACK_REJECTION: return FALLBACK_REJECTION;\n            case FALLBACK_DISABLED: return FALLBACK_DISABLED;\n            case FALLBACK_MISSING: return FALLBACK_MISSING;\n            case EXCEPTION_THROWN: return EXCEPTION_THROWN;\n            case RESPONSE_FROM_CACHE: return RESPONSE_FROM_CACHE;\n            case COLLAPSED: return COLLAPSED;\n            case BAD_REQUEST: return BAD_REQUEST;\n            case COMMAND_MAX_ACTIVE: return COMMAND_MAX_ACTIVE;\n            default:\n                throw new RuntimeException(\"Not an event that can be converted to HystrixEventType : \" + event);\n        }\n    }\n\n    /**\n     * List of events that throw an Exception to the caller\n     */\n    public final static List<HystrixEventType> EXCEPTION_PRODUCING_EVENT_TYPES = new ArrayList<HystrixEventType>();\n\n    /**\n     * List of events that are terminal\n     */\n    public final static List<HystrixEventType> TERMINAL_EVENT_TYPES = new ArrayList<HystrixEventType>();\n\n    static {\n        EXCEPTION_PRODUCING_EVENT_TYPES.add(BAD_REQUEST);\n        EXCEPTION_PRODUCING_EVENT_TYPES.add(FALLBACK_FAILURE);\n        EXCEPTION_PRODUCING_EVENT_TYPES.add(FALLBACK_DISABLED);\n        EXCEPTION_PRODUCING_EVENT_TYPES.add(FALLBACK_MISSING);\n        EXCEPTION_PRODUCING_EVENT_TYPES.add(FALLBACK_REJECTION);\n\n        for (HystrixEventType eventType: HystrixEventType.values()) {\n            if (eventType.isTerminal()) {\n                TERMINAL_EVENT_TYPES.add(eventType);\n            }\n        }\n    }\n\n    public enum ThreadPool {\n        EXECUTED, REJECTED;\n\n        public static ThreadPool from(HystrixRollingNumberEvent event) {\n            switch (event) {\n                case THREAD_EXECUTION: return EXECUTED;\n                case THREAD_POOL_REJECTED: return REJECTED;\n                default:\n                    throw new RuntimeException(\"Not an event that can be converted to HystrixEventType.ThreadPool : \" + event);\n            }\n        }\n\n        public static ThreadPool from(HystrixEventType eventType) {\n            switch (eventType) {\n                case SUCCESS: return EXECUTED;\n                case FAILURE: return EXECUTED;\n                case TIMEOUT: return EXECUTED;\n                case BAD_REQUEST: return EXECUTED;\n                case THREAD_POOL_REJECTED: return REJECTED;\n                default: return null;\n            }\n        }\n    }\n\n    public enum Collapser {\n        BATCH_EXECUTED, ADDED_TO_BATCH, RESPONSE_FROM_CACHE;\n\n        public static Collapser from(HystrixRollingNumberEvent event) {\n            switch (event) {\n                case COLLAPSER_BATCH: return BATCH_EXECUTED;\n                case COLLAPSER_REQUEST_BATCHED: return ADDED_TO_BATCH;\n                case RESPONSE_FROM_CACHE: return RESPONSE_FROM_CACHE;\n                default:\n                    throw new RuntimeException(\"Not an event that can be converted to HystrixEventType.Collapser : \" + event);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixExecutable.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.concurrent.Future;\n\nimport rx.Observable;\nimport rx.schedulers.Schedulers;\n\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\n/**\n * Common interface for executables ({@link HystrixCommand} and {@link HystrixCollapser}) so client code can treat them the same and combine in typed collections if desired.\n * \n * @param <R>\n */\npublic interface HystrixExecutable<R> extends HystrixInvokable<R> {\n\n    /**\n     * Used for synchronous execution of command.\n     * \n     * @return R\n     *         Result of {@link HystrixCommand} execution\n     * @throws HystrixRuntimeException\n     *             if an error occurs and a fallback cannot be retrieved\n     * @throws HystrixBadRequestException\n     *             if the {@link HystrixCommand} instance considers request arguments to be invalid and needs to throw an error that does not represent a system failure\n     */\n    public R execute();\n\n    /**\n     * Used for asynchronous execution of command.\n     * <p>\n     * This will queue up the command on the thread pool and return an {@link Future} to get the result once it completes.\n     * <p>\n     * NOTE: If configured to not run in a separate thread, this will have the same effect as {@link #execute()} and will block.\n     * <p>\n     * We don't throw an exception in that case but just flip to synchronous execution so code doesn't need to change in order to switch a circuit from running a separate thread to the calling thread.\n     * \n     * @return {@code Future<R>} Result of {@link HystrixCommand} execution\n     * @throws HystrixRuntimeException\n     *             if an error occurs and a fallback cannot be retrieved\n     * @throws HystrixBadRequestException\n     *             if the {@link HystrixCommand} instance considers request arguments to be invalid and needs to throw an error that does not represent a system failure\n     */\n    public Future<R> queue();\n\n    /**\n     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This eagerly starts execution of the command the same as {@link #queue()} and {@link #execute()}.\n     * A lazy {@link Observable} can be obtained from {@link HystrixCommand#toObservable()} or {@link HystrixCollapser#toObservable()}.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     *\n     * @return {@code Observable<R>} that executes and calls back with the result of the command execution or a fallback if the command fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Observer#onError} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Observer#onError} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Observable<R> observe();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixInvokable.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\n/**\n * Marker interface for Hystrix commands that can be invoked.\n */\npublic interface HystrixInvokable<R> {\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixInvokableInfo.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport java.util.List;\n\npublic interface HystrixInvokableInfo<R> {\n\n    HystrixCommandGroupKey getCommandGroup();\n\n    HystrixCommandKey getCommandKey();\n\n    HystrixThreadPoolKey getThreadPoolKey();\n\n    String getPublicCacheKey(); //have to use public in the name, as there's already a protected {@link AbstractCommand#getCacheKey()} method.\n\n    HystrixCollapserKey getOriginatingCollapserKey();\n\n    HystrixCommandMetrics getMetrics();\n\n    HystrixCommandProperties getProperties();\n\n    boolean isCircuitBreakerOpen();\n\n    boolean isExecutionComplete();\n\n    boolean isExecutedInThread();\n\n    boolean isSuccessfulExecution();\n\n    boolean isFailedExecution();\n\n    Throwable getFailedExecutionException();\n\n    boolean isResponseFromFallback();\n\n    boolean isResponseTimedOut();\n\n    boolean isResponseShortCircuited();\n\n    boolean isResponseFromCache();\n\n    boolean isResponseRejected();\n\n    boolean isResponseSemaphoreRejected();\n\n    boolean isResponseThreadPoolRejected();\n\n    List<HystrixEventType> getExecutionEvents();\n\n    int getNumberEmissions();\n\n    int getNumberFallbackEmissions();\n\n    int getNumberCollapsed();\n\n    int getExecutionTimeInMilliseconds();\n\n    long getCommandRunStartTimeInNanos();\n\n    ExecutionResult.EventCounts getEventCounts();\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixKey.java",
    "content": "package com.netflix.hystrix;\n\n/**\n * Basic class for hystrix keys\n */\npublic interface HystrixKey {\n    /**\n     * The word 'name' is used instead of 'key' so that Enums can implement this interface and it work natively.\n     *\n     * @return String\n     */\n    String name();\n\n    /**\n     * Default implementation of the interface\n     */\n    abstract class HystrixKeyDefault implements HystrixKey {\n        private final String name;\n\n        public HystrixKeyDefault(String name) {\n            this.name = name;\n        }\n\n        @Override\n        public String name() {\n            return name;\n        }\n\n        @Override\n        public String toString() {\n            return name;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixMetrics.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.util.HystrixRollingNumber;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\n\n/**\n * Abstract base class for Hystrix metrics\n */\npublic abstract class HystrixMetrics {\n\n    protected final HystrixRollingNumber counter;\n\n    protected HystrixMetrics(HystrixRollingNumber counter) {\n        this.counter = counter;\n    }\n    /**\n     * Get the cumulative count since the start of the application for the given {@link HystrixRollingNumberEvent}.\n     * \n     * @param event\n     *            {@link HystrixRollingNumberEvent} of the event to retrieve a sum for\n     * @return long cumulative count\n     */\n    public long getCumulativeCount(HystrixRollingNumberEvent event) {\n        return counter.getCumulativeSum(event);\n    }\n\n    /**\n     * Get the rolling count for the given {@link HystrixRollingNumberEvent}.\n     * <p>\n     * The rolling window is defined by {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()}.\n     * \n     * @param event\n     *            {@link HystrixRollingNumberEvent} of the event to retrieve a sum for\n     * @return long rolling count\n     */\n    public long getRollingCount(HystrixRollingNumberEvent event) {\n        return counter.getRollingSum(event);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservable.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport rx.Observable;\nimport rx.schedulers.Schedulers;\n\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\n/**\n * Common interface for executables that implement the Observable methods {@link #observe()} and {@link #toObservable()} so client code can treat them the same and combine in typed collections if desired.\n * \n * @param <R>\n */\npublic interface HystrixObservable<R> extends HystrixInvokable<R> {\n\n    /**\n     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This eagerly starts execution of the command the same as {@link HystrixCommand#queue()} and {@link HystrixCommand#execute()}.\n     * <p>\n     * A lazy {@link Observable} can be obtained from {@link #toObservable()}.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * <p>\n     * See https://github.com/ReactiveX/RxJava/wiki for more information.\n     *\n     * @return {@code Observable<R>} that executes and calls back with the result of the command execution or a fallback if the command execution fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Observer#onError} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Observer#onError} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Observable<R> observe();\n\n    /**\n     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This lazily starts execution of the command only once the {@link Observable} is subscribed to.\n     * <p>\n     * An eager {@link Observable} can be obtained from {@link #observe()}\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * <p>\n     * See https://github.com/ReactiveX/RxJava/wiki for more information.\n     *\n     * @return {@code Observable<R>} that executes and calls back with the result of the command execution or a fallback if the command execution fails for any reason.\n     * @throws HystrixRuntimeException\n     *             if a fallback does not exist\n     *             <p>\n     *             <ul>\n     *             <li>via {@code Observer#onError} if a failure occurs</li>\n     *             <li>or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)</li>\n     *             </ul>\n     * @throws HystrixBadRequestException\n     *             via {@code Observer#onError} if invalid arguments or state were used representing a user failure, not a system failure\n     * @throws IllegalStateException\n     *             if invoked more than once\n     */\n    public Observable<R> toObservable();\n    \n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCollapser.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.collapser.CollapserTimer;\nimport com.netflix.hystrix.collapser.HystrixCollapserBridge;\nimport com.netflix.hystrix.collapser.RealCollapserTimer;\nimport com.netflix.hystrix.collapser.RequestCollapser;\nimport com.netflix.hystrix.collapser.RequestCollapserFactory;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.schedulers.Schedulers;\nimport rx.subjects.ReplaySubject;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Collapse multiple requests into a single {@link HystrixCommand} execution based on a time window and optionally a max batch size.\n * <p>\n * This allows an object model to have multiple calls to the command that execute/queue many times in a short period (milliseconds) and have them all get batched into a single backend call.\n * <p>\n * Typically the time window is something like 10ms give or take.\n * <p>\n * NOTE: Do NOT retain any state within instances of this class.\n * <p>\n * It must be stateless or else it will be non-deterministic because most instances are discarded while some are retained and become the\n * \"collapsers\" for all the ones that are discarded.\n * \n * @param <K>\n *            The key used to match BatchReturnType and RequestArgumentType\n * @param <BatchReturnType>\n *            The type returned from the {@link HystrixCommand} that will be invoked on batch executions.\n * @param <ResponseType>\n *            The type returned from this command.\n * @param <RequestArgumentType>\n *            The type of the request argument. If multiple arguments are needed, wrap them in another object or a Tuple.\n */\npublic abstract class HystrixObservableCollapser<K, BatchReturnType, ResponseType, RequestArgumentType> implements HystrixObservable<ResponseType> {\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixObservableCollapser.class);\n\n    private final RequestCollapserFactory<BatchReturnType, ResponseType, RequestArgumentType> collapserFactory;\n    private final HystrixRequestCache requestCache;\n    private final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> collapserInstanceWrapper;\n    private final HystrixCollapserMetrics metrics;\n\n    /**\n     * The scope of request collapsing.\n     * <ul>\n     * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed.\n     * <p>\n     * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request.\n     * </li>\n     * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li>\n     * </ul>\n     */\n    public static enum Scope implements RequestCollapserFactory.Scope {\n        REQUEST, GLOBAL\n    }\n\n    /**\n     * Collapser with default {@link HystrixCollapserKey} derived from the implementing class name and scoped to {@link Scope#REQUEST} and default configuration.\n     */\n    protected HystrixObservableCollapser() {\n        this(Setter.withCollapserKey(null).andScope(Scope.REQUEST));\n    }\n\n    /**\n     * Collapser scoped to {@link Scope#REQUEST} and default configuration.\n     * \n     * @param collapserKey\n     *            {@link HystrixCollapserKey} that identifies this collapser and provides the key used for retrieving properties, request caches, publishing metrics etc.\n     */\n    protected HystrixObservableCollapser(HystrixCollapserKey collapserKey) {\n        this(Setter.withCollapserKey(collapserKey).andScope(Scope.REQUEST));\n    }\n\n    /**\n     * Construct a {@link HystrixObservableCollapser} with defined {@link Setter} that allows\n     * injecting property and strategy overrides and other optional arguments.\n     * <p>\n     * Null values will result in the default being used.\n     * \n     * @param setter\n     *            Fluent interface for constructor arguments\n     */\n    protected HystrixObservableCollapser(Setter setter) {\n        this(setter.collapserKey, setter.scope, new RealCollapserTimer(), setter.propertiesSetter, null);\n    }\n\n    /* package for tests */HystrixObservableCollapser(HystrixCollapserKey collapserKey, Scope scope, CollapserTimer timer, HystrixCollapserProperties.Setter propertiesBuilder, HystrixCollapserMetrics metrics) {\n        if (collapserKey == null || collapserKey.name().trim().equals(\"\")) {\n            String defaultKeyName = getDefaultNameFromClass(getClass());\n            collapserKey = HystrixCollapserKey.Factory.asKey(defaultKeyName);\n        }\n\n        HystrixCollapserProperties properties = HystrixPropertiesFactory.getCollapserProperties(collapserKey, propertiesBuilder);\n        this.collapserFactory = new RequestCollapserFactory<BatchReturnType, ResponseType, RequestArgumentType>(collapserKey, scope, timer, properties);\n        this.requestCache = HystrixRequestCache.getInstance(collapserKey, HystrixPlugins.getInstance().getConcurrencyStrategy());\n\n        if (metrics == null) {\n            this.metrics = HystrixCollapserMetrics.getInstance(collapserKey, properties);\n        } else {\n            this.metrics = metrics;\n        }\n\n        final HystrixObservableCollapser<K, BatchReturnType, ResponseType, RequestArgumentType> self = this;\n\n           /* strategy: HystrixMetricsPublisherCollapser */\n        HystrixMetricsPublisherFactory.createOrRetrievePublisherForCollapser(collapserKey, this.metrics, properties);\n\n\n        /**\n         * Used to pass public method invocation to the underlying implementation in a separate package while leaving the methods 'protected' in this class.\n         */\n        collapserInstanceWrapper = new HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType>() {\n\n            @Override\n            public Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shardRequests(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shards = self.shardRequests(requests);\n                self.metrics.markShards(shards.size());\n                return shards;\n            }\n\n            @Override\n            public Observable<BatchReturnType> createObservableCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                HystrixObservableCommand<BatchReturnType> command = self.createCommand(requests);\n\n                // mark the number of requests being collapsed together\n                command.markAsCollapsedCommand(this.getCollapserKey(), requests.size());\n                self.metrics.markBatch(requests.size());\n                return command.toObservable();\n            }\n\n            @Override\n            public Observable<Void> mapResponseToRequests(Observable<BatchReturnType> batchResponse, Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n                Func1<RequestArgumentType, K> requestKeySelector = self.getRequestArgumentKeySelector();\n                final Func1<BatchReturnType, K> batchResponseKeySelector = self.getBatchReturnTypeKeySelector();\n                final Func1<BatchReturnType, ResponseType> mapBatchTypeToResponseType = self.getBatchReturnTypeToResponseTypeMapper();\n\n                // index the requests by key\n                final Map<K, CollapsedRequest<ResponseType, RequestArgumentType>> requestsByKey = new HashMap<K, CollapsedRequest<ResponseType, RequestArgumentType>>(requests.size());\n                for (CollapsedRequest<ResponseType, RequestArgumentType> cr : requests) {\n                    K requestArg = requestKeySelector.call(cr.getArgument());\n                    requestsByKey.put(requestArg, cr);\n                }\n                final Set<K> seenKeys = new HashSet<K>();\n\n                // observe the responses and join with the requests by key\n                return batchResponse\n                        .doOnNext(new Action1<BatchReturnType>() {\n                            @Override\n                            public void call(BatchReturnType batchReturnType) {\n                                try {\n                                    K responseKey = batchResponseKeySelector.call(batchReturnType);\n                                    CollapsedRequest<ResponseType, RequestArgumentType> requestForResponse = requestsByKey.get(responseKey);\n                                    if (requestForResponse != null) {\n                                        requestForResponse.emitResponse(mapBatchTypeToResponseType.call(batchReturnType));\n                                        // now add this to seenKeys, so we can later check what was seen, and what was unseen\n                                        seenKeys.add(responseKey);\n                                    } else {\n                                        logger.warn(\"Batch Response contained a response key not in request batch : {}\", responseKey);\n                                    }\n                                } catch (Throwable ex) {\n                                    logger.warn(\"Uncaught error during demultiplexing of BatchResponse\", ex);\n                                }\n                            }\n                        })\n                        .doOnError(new Action1<Throwable>() {\n                            @Override\n                            public void call(Throwable t) {\n                                Exception ex = getExceptionFromThrowable(t);\n                                for (CollapsedRequest<ResponseType, RequestArgumentType> collapsedReq : requestsByKey.values()) {\n                                    collapsedReq.setException(ex);\n                                }\n                            }\n                        })\n                        .doOnCompleted(new Action0() {\n                            @Override\n                            public void call() {\n\n                                for (Map.Entry<K, CollapsedRequest<ResponseType, RequestArgumentType>> entry : requestsByKey.entrySet()) {\n                                    K key = entry.getKey();\n                                    CollapsedRequest<ResponseType, RequestArgumentType> collapsedReq = entry.getValue();\n                                    if (!seenKeys.contains(key)) {\n                                        try {\n                                            onMissingResponse(collapsedReq);\n                                        } catch (Throwable ex) {\n                                            collapsedReq.setException(new RuntimeException(\"Error in HystrixObservableCollapser.onMissingResponse handler\", ex));\n                                        }\n                                    }\n                                    //then unconditionally issue an onCompleted. this ensures the downstream gets a terminal, regardless of how onMissingResponse was implemented\n                                    collapsedReq.setComplete();\n                                }\n                            }\n                        }).ignoreElements().cast(Void.class);\n            }\n\n            @Override\n            public HystrixCollapserKey getCollapserKey() {\n                return self.getCollapserKey();\n            }\n\n        };\n    }\n\n    protected Exception getExceptionFromThrowable(Throwable t) {\n        Exception e;\n        if (t instanceof Exception) {\n            e = (Exception) t;\n        } else {\n            // Hystrix 1.x uses Exception, not Throwable so to prevent a breaking change Throwable will be wrapped in Exception\n            e = new Exception(\"Throwable caught while executing.\", t);\n        }\n        return e;\n    }\n\n\n    private HystrixCollapserProperties getProperties() {\n        return collapserFactory.getProperties();\n    }\n\n    /**\n     * Key of the {@link HystrixObservableCollapser} used for properties, metrics, caches, reporting etc.\n     * \n     * @return {@link HystrixCollapserKey} identifying this {@link HystrixObservableCollapser} instance\n     */\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserFactory.getCollapserKey();\n    }\n\n    /**\n     * Scope of collapsing.\n     * <p>\n     * <ul>\n     * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed.\n     * <p>\n     * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request.\n     * </li>\n     * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li>\n     * </ul>\n     * <p>\n     * Default: {@link Scope#REQUEST} (defined via constructor)\n     * \n     * @return {@link Scope} that collapsing should be performed within.\n     */\n    public Scope getScope() {\n        return Scope.valueOf(collapserFactory.getScope().name());\n    }\n\n    /**\n     * Return the {@link HystrixCollapserMetrics} for this collapser\n     * @return {@link HystrixCollapserMetrics} for this collapser\n     */\n    public HystrixCollapserMetrics getMetrics() {\n        return metrics;\n    }\n\n    /**\n     * The request arguments to be passed to the {@link HystrixCommand}.\n     * <p>\n     * Typically this means to take the argument(s) provided to the constructor and return it here.\n     * <p>\n     * If there are multiple arguments that need to be bundled, create a single object to contain them, or use a Tuple.\n     * \n     * @return RequestArgumentType\n     */\n    public abstract RequestArgumentType getRequestArgument();\n\n    /**\n     * Factory method to create a new {@link HystrixObservableCommand}{@code <BatchReturnType>} command object each time a batch needs to be executed.\n     * <p>\n     * Do not return the same instance each time. Return a new instance on each invocation.\n     * <p>\n     * Process the 'requests' argument into the arguments the command object needs to perform its work.\n     * <p>\n     * If a batch or requests needs to be split (sharded) into multiple commands, see {@link #shardRequests} <p>\n     * IMPLEMENTATION NOTE: Be fast (ie. <1ms) in this method otherwise it can block the Timer from executing subsequent batches. Do not do any processing beyond constructing the command and returning\n     * it.\n     * \n     * @param requests\n     *            {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} containing {@link CollapsedRequest} objects containing the arguments of each request collapsed in this batch.\n     * @return {@link HystrixObservableCommand}{@code <BatchReturnType>} which when executed will retrieve results for the batch of arguments as found in the Collection of {@link CollapsedRequest}\n     *         objects\n     */\n    protected abstract HystrixObservableCommand<BatchReturnType> createCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    /**\n     * Override to split (shard) a batch of requests into multiple batches that will each call <code>createCommand</code> separately.\n     * <p>\n     * The purpose of this is to allow collapsing to work for services that have sharded backends and batch executions that need to be shard-aware.\n     * <p>\n     * For example, a batch of 100 requests could be split into 4 different batches sharded on name (ie. a-g, h-n, o-t, u-z) that each result in a separate {@link HystrixCommand} being created and\n     * executed for them.\n     * <p>\n     * By default this method does nothing to the Collection and is a pass-thru.\n     * \n     * @param requests\n     *            {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} containing {@link CollapsedRequest} objects containing the arguments of each request collapsed in this batch.\n     * @return Collection of {@code Collection<CollapsedRequest<ResponseType, RequestArgumentType>>} objects sharded according to business rules.\n     *         <p>The CollapsedRequest instances should not be modified or wrapped as the CollapsedRequest instance object contains state information needed to complete the execution.\n     */\n    protected Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shardRequests(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests) {\n        return Collections.singletonList(requests);\n    }\n\n    /**\n     * Function that returns the key used for matching returned objects against request argument types.\n     * <p>\n     * The key returned from this function should match up with the key returned from {@link #getRequestArgumentKeySelector()};\n     * \n     * @return key selector function\n     */\n    protected abstract Func1<BatchReturnType, K> getBatchReturnTypeKeySelector();\n\n    /**\n     * Function that returns the key used for matching request arguments against returned objects.\n     * <p>\n     * The key returned from this function should match up with the key returned from {@link #getBatchReturnTypeKeySelector()};\n     * \n     * @return key selector function\n     */\n    protected abstract Func1<RequestArgumentType, K> getRequestArgumentKeySelector();\n\n    /**\n     * Invoked if a {@link CollapsedRequest} in the batch does not have a response set on it.\n     * <p>\n     * This allows setting an exception (via {@link CollapsedRequest#setException(Exception)}) or a fallback response (via {@link CollapsedRequest#setResponse(Object)}).\n     * \n     * @param r {@link CollapsedRequest}\n     *            that needs a response or exception set on it.\n     */\n    protected abstract void onMissingResponse(CollapsedRequest<ResponseType, RequestArgumentType> r);\n\n    /**\n     * Function for mapping from BatchReturnType to ResponseType.\n     * <p>\n     * Often these two types are exactly the same so it's just a pass-thru.\n     * \n     * @return function for mapping from BatchReturnType to ResponseType\n     */\n    protected abstract Func1<BatchReturnType, ResponseType> getBatchReturnTypeToResponseTypeMapper();\n\n    /**\n     * Used for asynchronous execution with a callback by subscribing to the {@link Observable}.\n     * <p>\n     * This eagerly starts execution the same as {@link HystrixCollapser#queue()} and {@link HystrixCollapser#execute()}.\n     * A lazy {@link Observable} can be obtained from {@link #toObservable()}.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * Use {@link #toObservable(rx.Scheduler)} to schedule the callback differently.\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after mapping\n     *         the {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> observe() {\n        // use a ReplaySubject to buffer the eagerly subscribed-to Observable\n        ReplaySubject<ResponseType> subject = ReplaySubject.create();\n        // eagerly kick off subscription\n        final Subscription underlyingSubscription = toObservable().subscribe(subject);\n        // return the subject that can be subscribed to later while the execution has already started\n        return subject.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                underlyingSubscription.unsubscribe();\n            }\n        });\n    }\n\n    /**\n     * A lazy {@link Observable} that will execute when subscribed to.\n     * <p>\n     * <b>Callback Scheduling</b>\n     * <p>\n     * <ul>\n     * <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>\n     * <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>\n     * </ul>\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @return {@code Observable<R>} that lazily executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after mapping the\n     * {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> toObservable() {\n        // when we callback with the data we want to do the work\n        // on a separate thread than the one giving us the callback\n        return toObservable(Schedulers.computation());\n    }\n\n    /**\n     * A lazy {@link Observable} that will execute when subscribed to.\n     * <p>\n     * See https://github.com/Netflix/RxJava/wiki for more information.\n     * \n     * @param observeOn\n     *            The {@link Scheduler} to execute callbacks on.\n     * @return {@code Observable<R>} that lazily executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after mapping the\n     * {@code <BatchReturnType>} into {@code <ResponseType>}\n     */\n    public Observable<ResponseType> toObservable(Scheduler observeOn) {\n\n        return Observable.defer(new Func0<Observable<ResponseType>>() {\n            @Override\n            public Observable<ResponseType> call() {\n                final boolean isRequestCacheEnabled = getProperties().requestCacheEnabled().get();\n\n                /* try from cache first */\n                if (isRequestCacheEnabled) {\n                    HystrixCachedObservable<ResponseType> fromCache = requestCache.get(getCacheKey());\n                    if (fromCache != null) {\n                        metrics.markResponseFromCache();\n                        return fromCache.toObservable();\n                    }\n                }\n\n                RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> requestCollapser = collapserFactory.getRequestCollapser(collapserInstanceWrapper);\n                Observable<ResponseType> response = requestCollapser.submitRequest(getRequestArgument());\n                metrics.markRequestBatched();\n                if (isRequestCacheEnabled) {\n                    /*\n                     * A race can occur here with multiple threads queuing but only one will be cached.\n                     * This means we can have some duplication of requests in a thread-race but we're okay\n                     * with having some inefficiency in duplicate requests in the same batch\n                     * and then subsequent requests will retrieve a previously cached Observable.\n                     *\n                     * If this is an issue we can make a lazy-future that gets set in the cache\n                     * then only the winning 'put' will be invoked to actually call 'submitRequest'\n                     */\n                    HystrixCachedObservable<ResponseType> toCache = HystrixCachedObservable.from(response);\n                    HystrixCachedObservable<ResponseType> fromCache = requestCache.putIfAbsent(getCacheKey(), toCache);\n                    if (fromCache == null) {\n                        return toCache.toObservable();\n                    } else {\n                        return fromCache.toObservable();\n                    }\n                }\n                return response;\n            }\n        });\n    }\n\n    /**\n     * Key to be used for request caching.\n     * <p>\n     * By default this returns null which means \"do not cache\".\n     * <p>\n     * To enable caching override this method and return a string key uniquely representing the state of a command instance.\n     * <p>\n     * If multiple command instances in the same request scope match keys then only the first will be executed and all others returned from cache.\n     * \n     * @return String cacheKey or null if not to cache\n     */\n    protected String getCacheKey() {\n        return null;\n    }\n\n    /**\n     * Clears all state. If new requests come in instances will be recreated and metrics started from scratch.\n     */\n    /* package */static void reset() {\n        RequestCollapserFactory.reset();\n    }\n\n    private static String getDefaultNameFromClass(@SuppressWarnings(\"rawtypes\") Class<? extends HystrixObservableCollapser> cls) {\n        String fromCache = defaultNameCache.get(cls);\n        if (fromCache != null) {\n            return fromCache;\n        }\n        // generate the default\n        // default HystrixCommandKey to use if the method is not overridden\n        String name = cls.getSimpleName();\n        if (name.equals(\"\")) {\n            // we don't have a SimpleName (anonymous inner class) so use the full class name\n            name = cls.getName();\n            name = name.substring(name.lastIndexOf('.') + 1, name.length());\n        }\n        defaultNameCache.put(cls, name);\n        return name;\n    }\n\n    /**\n     * Fluent interface for arguments to the {@link HystrixObservableCollapser} constructor.\n     * <p>\n     * The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods.\n     * <p>\n     * Example:\n     * <pre> {@code\n     *  Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey(\"CollapserName\"))\n                .andScope(Scope.REQUEST);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    public static class Setter {\n        private final HystrixCollapserKey collapserKey;\n        private Scope scope = Scope.REQUEST; // default if nothing is set\n        private HystrixCollapserProperties.Setter propertiesSetter;\n\n        private Setter(HystrixCollapserKey collapserKey) {\n            this.collapserKey = collapserKey;\n        }\n\n        /**\n         * Setter factory method containing required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param collapserKey\n         *            {@link HystrixCollapserKey} that identifies this collapser and provides the key used for retrieving properties, request caches, publishing metrics etc.\n         * @return Setter for fluent interface via method chaining\n         */\n        public static Setter withCollapserKey(HystrixCollapserKey collapserKey) {\n            return new Setter(collapserKey);\n        }\n\n        /**\n         * {@link Scope} defining what scope the collapsing should occur within\n         * \n         * @param scope collapser scope\n         * \n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andScope(Scope scope) {\n            this.scope = scope;\n            return this;\n        }\n\n        /**\n         * @param propertiesSetter\n         *            {@link HystrixCollapserProperties.Setter} that allows instance specific property overrides (which can then be overridden by dynamic properties, see\n         *            {@link HystrixPropertiesStrategy} for\n         *            information on order of precedence).\n         *            <p>\n         *            Will use defaults if left NULL.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter propertiesSetter) {\n            this.propertiesSetter = propertiesSetter;\n            return this;\n        }\n\n    }\n\n    // this is a micro-optimization but saves about 1-2microseconds (on 2011 MacBook Pro) \n    // on the repetitive string processing that will occur on the same classes over and over again\n    @SuppressWarnings(\"rawtypes\")\n    private static ConcurrentHashMap<Class<? extends HystrixObservableCollapser>, String> defaultNameCache = new ConcurrentHashMap<Class<? extends HystrixObservableCollapser>, String>();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport rx.Observable;\n\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\n\n/**\n * Used to wrap code that will execute potentially risky functionality (typically meaning a service call over the network)\n * with fault and latency tolerance, statistics and performance metrics capture, circuit breaker and bulkhead functionality.\n * This command should be used for a purely non-blocking call pattern. The caller of this command will be subscribed to the Observable<R> returned by the run() method.\n * \n * @param <R>\n *            the return type\n * \n * @ThreadSafe\n */\npublic abstract class HystrixObservableCommand<R> extends AbstractCommand<R> implements HystrixObservable<R>, HystrixInvokableInfo<R> {\n\n    /**\n     * Construct a {@link HystrixObservableCommand} with defined {@link HystrixCommandGroupKey}.\n     * <p>\n     * The {@link HystrixCommandKey} will be derived from the implementing class name.\n     * \n     * @param group\n     *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects.\n     *            <p>\n     *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace with,\n     *            common business purpose etc.\n     */\n    protected HystrixObservableCommand(HystrixCommandGroupKey group) {\n        // use 'null' to specify use the default\n        this(new Setter(group));\n    }\n\n    /**\n     *\n     * Overridden to true so that all onNext emissions are captured\n     *\n     * @return if onNext events should be reported on\n     * This affects {@link HystrixRequestLog}, and {@link HystrixEventNotifier} currently.  Metrics/Hooks later\n     */\n    @Override\n    protected boolean shouldOutputOnNextEvents() {\n        return true;\n    }\n\n    @Override\n    protected String getFallbackMethodName() {\n        return \"resumeWithFallback\";\n    }\n\n    @Override\n    protected boolean isFallbackUserDefined() {\n        Boolean containsFromMap = commandContainsFallback.get(commandKey);\n        if (containsFromMap != null) {\n            return containsFromMap;\n        } else {\n            Boolean toInsertIntoMap;\n            try {\n                getClass().getDeclaredMethod(\"resumeWithFallback\");\n                toInsertIntoMap = true;\n            } catch (NoSuchMethodException nsme) {\n                toInsertIntoMap = false;\n            }\n            commandContainsFallback.put(commandKey, toInsertIntoMap);\n            return toInsertIntoMap;\n        }\n    }\n\n    @Override\n    protected boolean commandIsScalar() {\n        return false;\n    }\n\n    /**\n     * Construct a {@link HystrixObservableCommand} with defined {@link Setter} that allows injecting property and strategy overrides and other optional arguments.\n     * <p>\n     * NOTE: The {@link HystrixCommandKey} is used to associate a {@link HystrixObservableCommand} with {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and other objects.\n     * <p>\n     * Do not create multiple {@link HystrixObservableCommand} implementations with the same {@link HystrixCommandKey} but different injected default properties as the first instantiated will win.\n     * <p>\n     * Properties passed in via {@link Setter#andCommandPropertiesDefaults} are cached for the given {@link HystrixCommandKey} for the life of the JVM\n     * or until {@link Hystrix#reset()} is called. Dynamic properties allow runtime changes. Read more on the <a href=\"https://github.com/Netflix/Hystrix/wiki/Configuration\">Hystrix Wiki</a>.\n     * \n     * @param setter\n     *            Fluent interface for constructor arguments\n     */\n    protected HystrixObservableCommand(Setter setter) {\n        // use 'null' to specify use the default\n        this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);\n    }\n\n    /**\n     * Allow constructing a {@link HystrixObservableCommand} with injection of most aspects of its functionality.\n     * <p>\n     * Some of these never have a legitimate reason for injection except in unit testing.\n     * <p>\n     * Most of the args will revert to a valid default if 'null' is passed in.\n     */\n    HystrixObservableCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,\n            HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,\n            HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,\n            HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {\n        super(group, key, threadPoolKey, circuitBreaker, threadPool, commandPropertiesDefaults, threadPoolPropertiesDefaults, metrics, fallbackSemaphore, executionSemaphore, propertiesStrategy, executionHook);\n    }\n\n    /**\n     * Fluent interface for arguments to the {@link HystrixObservableCommand} constructor.\n     * <p>\n     * The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods.\n     * <p>\n     * Example:\n     * <pre> {@code\n     *  Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GroupName\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"CommandName\"))\n                .andEventNotifier(notifier);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    final public static class Setter {\n\n        protected final HystrixCommandGroupKey groupKey;\n        protected HystrixCommandKey commandKey;\n        protected HystrixThreadPoolKey threadPoolKey;\n        protected HystrixCommandProperties.Setter commandPropertiesDefaults;\n        protected HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults;\n\n        /**\n         * Setter factory method containing required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param groupKey\n         *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects.\n         *            <p>\n         *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace\n         *            with,\n         *            common business purpose etc.\n         */\n        protected Setter(HystrixCommandGroupKey groupKey) {\n            this.groupKey = groupKey;\n\n            // default to using SEMAPHORE for ObservableCommand\n            commandPropertiesDefaults = setDefaults(HystrixCommandProperties.Setter());\n        }\n\n        /**\n         * Setter factory method with required values.\n         * <p>\n         * All optional arguments can be set via the chained methods.\n         * \n         * @param groupKey\n         *            {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects.\n         *            <p>\n         *            The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace\n         *            with,\n         *            common business purpose etc.\n         */\n        public static Setter withGroupKey(HystrixCommandGroupKey groupKey) {\n            return new Setter(groupKey);\n        }\n\n        /**\n         * @param commandKey\n         *            {@link HystrixCommandKey} used to identify a {@link HystrixObservableCommand} instance for statistics, circuit-breaker, properties, etc.\n         *            <p>\n         *            By default this will be derived from the instance class name.\n         *            <p>\n         *            NOTE: Every unique {@link HystrixCommandKey} will result in new instances of {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and {@link HystrixCommandProperties}.\n         *            Thus,\n         *            the number of variants should be kept to a finite and reasonable number to avoid high-memory usage or memory leacks.\n         *            <p>\n         *            Hundreds of keys is fine, tens of thousands is probably not.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCommandKey(HystrixCommandKey commandKey) {\n            this.commandKey = commandKey;\n            return this;\n        }\n\n        /**\n         * Optional\n         * \n         * @param commandPropertiesDefaults\n         *            {@link HystrixCommandProperties.Setter} with property overrides for this specific instance of {@link HystrixObservableCommand}.\n         *            <p>\n         *            See the {@link HystrixPropertiesStrategy} JavaDocs for more information on properties and order of precedence.\n         * @return Setter for fluent interface via method chaining\n         */\n        public Setter andCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) {\n            this.commandPropertiesDefaults = setDefaults(commandPropertiesDefaults);\n            return this;\n        }\n\n        private HystrixCommandProperties.Setter setDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) {\n            if (commandPropertiesDefaults.getExecutionIsolationStrategy() == null) {\n                // default to using SEMAPHORE for ObservableCommand if the user didn't set it\n                commandPropertiesDefaults.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE);\n            }\n            return commandPropertiesDefaults;\n        }\n\n    }\n\n    /**\n     * Implement this method with code to be executed when {@link #observe()} or {@link #toObservable()} are invoked.\n     * \n     * @return R response type\n     */\n    protected abstract Observable<R> construct();\n\n    /**\n     * If {@link #observe()} or {@link #toObservable()} fails in any way then this method will be invoked to provide an opportunity to return a fallback response.\n     * <p>\n     * This should do work that does not require network transport to produce.\n     * <p>\n     * In other words, this should be a static or cached result that can immediately be returned upon failure.\n     * <p>\n     * If network traffic is wanted for fallback (such as going to MemCache) then the fallback implementation should invoke another {@link HystrixObservableCommand} instance that protects against\n     * that network\n     * access and possibly has another level of fallback that does not involve network access.\n     * <p>\n     * DEFAULT BEHAVIOR: It throws UnsupportedOperationException.\n     * \n     * @return R or UnsupportedOperationException if not implemented\n     */\n    protected Observable<R> resumeWithFallback() {\n        return Observable.error(new UnsupportedOperationException(\"No fallback available.\"));\n    }\n\n    @Override\n    final protected Observable<R> getExecutionObservable() {\n        return construct();\n    }\n    \n    @Override\n    final protected Observable<R> getFallbackObservable() {\n        return resumeWithFallback();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestCache.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableHolder;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Observable;\nimport rx.internal.operators.CachedObservable;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Cache that is scoped to the current request as managed by {@link HystrixRequestVariableDefault}.\n * <p>\n * This is used for short-lived caching of {@link HystrixCommand} instances to allow de-duping of command executions within a request.\n */\npublic class HystrixRequestCache {\n    @SuppressWarnings(\"unused\")\n    private static final Logger logger = LoggerFactory.getLogger(HystrixRequestCache.class);\n\n    // the String key must be: HystrixRequestCache.prefix + concurrencyStrategy + cacheKey\n    private final static ConcurrentHashMap<RequestCacheKey, HystrixRequestCache> caches = new ConcurrentHashMap<RequestCacheKey, HystrixRequestCache>();\n\n    private final RequestCacheKey rcKey;\n    private final HystrixConcurrencyStrategy concurrencyStrategy;\n\n    /**\n     * A ConcurrentHashMap per 'prefix' and per request scope that is used to to dedupe requests in the same request.\n     * <p>\n     * Key => CommandPrefix + CacheKey : Future<?> from queue()\n     */\n    private static final HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>> requestVariableForCache = new HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>(new HystrixRequestVariableLifecycle<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>() {\n\n        @Override\n        public ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> initialValue() {\n            return new ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>();\n        }\n\n        @Override\n        public void shutdown(ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> value) {\n            // nothing to shutdown\n        }\n\n    });\n\n    private HystrixRequestCache(RequestCacheKey rcKey, HystrixConcurrencyStrategy concurrencyStrategy) {\n        this.rcKey = rcKey;\n        this.concurrencyStrategy = concurrencyStrategy;\n    }\n\n    public static HystrixRequestCache getInstance(HystrixCommandKey key, HystrixConcurrencyStrategy concurrencyStrategy) {\n        return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);\n    }\n\n    public static HystrixRequestCache getInstance(HystrixCollapserKey key, HystrixConcurrencyStrategy concurrencyStrategy) {\n        return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);\n    }\n\n    private static HystrixRequestCache getInstance(RequestCacheKey rcKey, HystrixConcurrencyStrategy concurrencyStrategy) {\n        HystrixRequestCache c = caches.get(rcKey);\n        if (c == null) {\n            HystrixRequestCache newRequestCache = new HystrixRequestCache(rcKey, concurrencyStrategy);\n            HystrixRequestCache existing = caches.putIfAbsent(rcKey, newRequestCache);\n            if (existing == null) {\n                // we won so use the new one\n                c = newRequestCache;\n            } else {\n                // we lost so use the existing\n                c = existing;\n            }\n        }\n        return c;\n    }\n\n    /**\n     * Retrieve a cached Future for this request scope if a matching command has already been executed/queued.\n     * \n     * @return {@code Future<T>}\n     */\n    // suppressing warnings because we are using a raw Future since it's in a heterogeneous ConcurrentHashMap cache\n    @SuppressWarnings({ \"unchecked\" })\n    /* package */<T> HystrixCachedObservable<T> get(String cacheKey) {\n        ValueCacheKey key = getRequestCacheKey(cacheKey);\n        if (key != null) {\n            ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);\n            if (cacheInstance == null) {\n                throw new IllegalStateException(\"Request caching is not available. Maybe you need to initialize the HystrixRequestContext?\");\n            }\n            /* look for the stored value */\n            return (HystrixCachedObservable<T>) cacheInstance.get(key);\n        }\n        return null;\n    }\n\n    /**\n     * Put the Future in the cache if it does not already exist.\n     * <p>\n     * If this method returns a non-null value then another thread won the race and it should be returned instead of proceeding with execution of the new Future.\n     * \n     * @param cacheKey\n     *            key as defined by {@link HystrixCommand#getCacheKey()}\n     * @param f\n     *            Future to be cached\n     * \n     * @return null if nothing else was in the cache (or this {@link HystrixCommand} does not have a cacheKey) or previous value if another thread beat us to adding to the cache\n     */\n    // suppressing warnings because we are using a raw Future since it's in a heterogeneous ConcurrentHashMap cache\n    @SuppressWarnings({ \"unchecked\" })\n    /* package */<T> HystrixCachedObservable<T> putIfAbsent(String cacheKey, HystrixCachedObservable<T> f) {\n        ValueCacheKey key = getRequestCacheKey(cacheKey);\n        if (key != null) {\n            /* look for the stored value */\n            ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);\n            if (cacheInstance == null) {\n                throw new IllegalStateException(\"Request caching is not available. Maybe you need to initialize the HystrixRequestContext?\");\n            }\n            HystrixCachedObservable<T> alreadySet = (HystrixCachedObservable<T>) cacheInstance.putIfAbsent(key, f);\n            if (alreadySet != null) {\n                // someone beat us so we didn't cache this\n                return alreadySet;\n            }\n        }\n        // we either set it in the cache or do not have a cache key\n        return null;\n    }\n\n    /**\n     * Clear the cache for a given cacheKey.\n     * \n     * @param cacheKey\n     *            key as defined by {@link HystrixCommand#getCacheKey()}\n     */\n    public void clear(String cacheKey) {\n        ValueCacheKey key = getRequestCacheKey(cacheKey);\n        if (key != null) {\n            ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);\n            if (cacheInstance == null) {\n                throw new IllegalStateException(\"Request caching is not available. Maybe you need to initialize the HystrixRequestContext?\");\n            }\n\n            /* remove this cache key */\n            cacheInstance.remove(key);\n        }\n    }\n\n    /**\n     * Request CacheKey: HystrixRequestCache.prefix + concurrencyStrategy + HystrixCommand.getCacheKey (as injected via get/put to this class)\n     * <p>\n     * We prefix with {@link HystrixCommandKey} or {@link HystrixCollapserKey} since the cache is heterogeneous and we don't want to accidentally return cached Futures from different\n     * types.\n     * \n     * @return ValueCacheKey\n     */\n    private ValueCacheKey getRequestCacheKey(String cacheKey) {\n        if (cacheKey != null) {\n            /* create the cache key we will use to retrieve/store that include the type key prefix */\n            return new ValueCacheKey(rcKey, cacheKey);\n        }\n        return null;\n    }\n\n    private static class ValueCacheKey {\n        private final RequestCacheKey rvKey;\n        private final String valueCacheKey;\n\n        private ValueCacheKey(RequestCacheKey rvKey, String valueCacheKey) {\n            this.rvKey = rvKey;\n            this.valueCacheKey = valueCacheKey;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + ((rvKey == null) ? 0 : rvKey.hashCode());\n            result = prime * result + ((valueCacheKey == null) ? 0 : valueCacheKey.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj)\n                return true;\n            if (obj == null)\n                return false;\n            if (getClass() != obj.getClass())\n                return false;\n            ValueCacheKey other = (ValueCacheKey) obj;\n            if (rvKey == null) {\n                if (other.rvKey != null)\n                    return false;\n            } else if (!rvKey.equals(other.rvKey))\n                return false;\n            if (valueCacheKey == null) {\n                if (other.valueCacheKey != null)\n                    return false;\n            } else if (!valueCacheKey.equals(other.valueCacheKey))\n                return false;\n            return true;\n        }\n\n    }\n\n    private static class RequestCacheKey {\n        private final short type; // used to differentiate between Collapser/Command if key is same between them\n        private final String key;\n        private final HystrixConcurrencyStrategy concurrencyStrategy;\n\n        private RequestCacheKey(HystrixCommandKey commandKey, HystrixConcurrencyStrategy concurrencyStrategy) {\n            type = 1;\n            if (commandKey == null) {\n                this.key = null;\n            } else {\n                this.key = commandKey.name();\n            }\n            this.concurrencyStrategy = concurrencyStrategy;\n        }\n\n        private RequestCacheKey(HystrixCollapserKey collapserKey, HystrixConcurrencyStrategy concurrencyStrategy) {\n            type = 2;\n            if (collapserKey == null) {\n                this.key = null;\n            } else {\n                this.key = collapserKey.name();\n            }\n            this.concurrencyStrategy = concurrencyStrategy;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + ((concurrencyStrategy == null) ? 0 : concurrencyStrategy.hashCode());\n            result = prime * result + ((key == null) ? 0 : key.hashCode());\n            result = prime * result + type;\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj)\n                return true;\n            if (obj == null)\n                return false;\n            if (getClass() != obj.getClass())\n                return false;\n            RequestCacheKey other = (RequestCacheKey) obj;\n            if (type != other.type)\n                return false;\n            if (key == null) {\n                if (other.key != null)\n                    return false;\n            } else if (!key.equals(other.key))\n                return false;\n            if (concurrencyStrategy == null) {\n                if (other.concurrencyStrategy != null)\n                    return false;\n            } else if (!concurrencyStrategy.equals(other.concurrencyStrategy))\n                return false;\n            return true;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.metric.HystrixRequestEventsStream;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableHolder;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.LinkedBlockingQueue;\n\n/**\n * Log of {@link HystrixCommand} executions and events during the current request.\n */\npublic class HystrixRequestLog {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixRequestLog.class);\n\n    /**\n     * RequestLog: Reduce Chance of Memory Leak\n     * https://github.com/Netflix/Hystrix/issues/53\n     * \n     * Upper limit on RequestLog before ignoring further additions and logging warnings.\n     * \n     * Intended to help prevent memory leaks when someone isn't aware of the\n     * HystrixRequestContext lifecycle or enabling/disabling RequestLog.\n     */\n    /* package */static final int MAX_STORAGE = 1000;\n\n    private static final HystrixRequestVariableHolder<HystrixRequestLog> currentRequestLog = new HystrixRequestVariableHolder<HystrixRequestLog>(new HystrixRequestVariableLifecycle<HystrixRequestLog>() {\n        @Override\n        public HystrixRequestLog initialValue() {\n            return new HystrixRequestLog();\n        }\n\n        public void shutdown(HystrixRequestLog value) {\n            //write this value to the Request stream\n            HystrixRequestEventsStream.getInstance().write(value.getAllExecutedCommands());\n        }\n    });\n\n    /**\n     * History of {@link HystrixCommand} executed in this request.\n     */\n    private LinkedBlockingQueue<HystrixCommand<?>> executedCommands = new LinkedBlockingQueue<HystrixCommand<?>>(MAX_STORAGE);\n\n    /**\n     * History of {@link HystrixInvokableInfo} executed in this request.\n     */\n    private LinkedBlockingQueue<HystrixInvokableInfo<?>> allExecutedCommands = new LinkedBlockingQueue<HystrixInvokableInfo<?>>(MAX_STORAGE);\n\n    // prevent public instantiation\n    private HystrixRequestLog() {\n    }\n\n    /**\n     * {@link HystrixRequestLog} for current request as defined by {@link HystrixRequestContext}.\n     * \n     * @return {@link HystrixRequestLog}\n     */\n    public static HystrixRequestLog getCurrentRequest(HystrixConcurrencyStrategy concurrencyStrategy) {\n        return currentRequestLog.get(concurrencyStrategy);\n    }\n\n    /**\n     * {@link HystrixRequestLog} for current request as defined by {@link HystrixRequestContext}.\n     * <p>\n     * NOTE: This uses the default {@link HystrixConcurrencyStrategy} or global override. If an injected strategy is being used by commands you must instead use\n     * {@link #getCurrentRequest(HystrixConcurrencyStrategy)}.\n     * \n     * @return {@link HystrixRequestLog}\n     */\n    public static HystrixRequestLog getCurrentRequest() {\n        return currentRequestLog.get(HystrixPlugins.getInstance().getConcurrencyStrategy());\n    }\n\n    /**\n     * Retrieve {@link HystrixCommand} instances that were executed during this {@link HystrixRequestContext}.\n     * \n     * @return {@code Collection<HystrixCommand<?>>}\n     */\n    @Deprecated\n    public Collection<HystrixCommand<?>> getExecutedCommands() {\n        return Collections.unmodifiableCollection(executedCommands);\n    }\n\n    /**\n     * Retrieve {@link HystrixCommand} instances that were executed during this {@link HystrixRequestContext}.\n     * \n     * @return {@code Collection<HystrixCommand<?>>}\n     */\n    public Collection<HystrixInvokableInfo<?>> getAllExecutedCommands() {\n        return Collections.unmodifiableCollection(allExecutedCommands);\n    }\n\n    /**\n     * Add {@link HystrixCommand} instance to the request log.\n     * \n     * @param command\n     *            {@code HystrixCommand<?>}\n     */\n    /* package */void addExecutedCommand(HystrixInvokableInfo<?> command) {\n        if (!allExecutedCommands.offer(command)) {\n            // see RequestLog: Reduce Chance of Memory Leak https://github.com/Netflix/Hystrix/issues/53\n            logger.warn(\"RequestLog ignoring command after reaching limit of \" + MAX_STORAGE + \". See https://github.com/Netflix/Hystrix/issues/53 for more information.\");\n        }\n\n        // TODO remove this when deprecation completed\n        if (command instanceof HystrixCommand) {\n            @SuppressWarnings(\"rawtypes\")\n            HystrixCommand<?> _c = (HystrixCommand) command;\n            if (!executedCommands.offer(_c)) {\n                // see RequestLog: Reduce Chance of Memory Leak https://github.com/Netflix/Hystrix/issues/53\n                logger.warn(\"RequestLog ignoring command after reaching limit of \" + MAX_STORAGE + \". See https://github.com/Netflix/Hystrix/issues/53 for more information.\");\n            }\n        }\n    }\n\n    /**\n     * Formats the log of executed commands into a string usable for logging purposes.\n     * <p>\n     * Examples:\n     * <ul>\n     * <li>TestCommand[SUCCESS][1ms]</li>\n     * <li>TestCommand[SUCCESS][1ms], TestCommand[SUCCESS, RESPONSE_FROM_CACHE][1ms]x4</li>\n     * <li>TestCommand[TIMEOUT][1ms]</li>\n     * <li>TestCommand[FAILURE][1ms]</li>\n     * <li>TestCommand[THREAD_POOL_REJECTED][1ms]</li>\n     * <li>TestCommand[THREAD_POOL_REJECTED, FALLBACK_SUCCESS][1ms]</li>\n     * <li>TestCommand[EMIT, SUCCESS][1ms]</li>\n     * <li>TestCommand[EMITx5, SUCCESS][1ms]</li>\n     * <li>TestCommand[EMITx5, FAILURE, FALLBACK_EMITx6, FALLBACK_FAILURE][100ms]</li>\n     * <li>TestCommand[FAILURE, FALLBACK_SUCCESS][1ms], TestCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][1ms]x4</li>\n     * <li>GetData[SUCCESS][1ms], PutData[SUCCESS][1ms], GetValues[SUCCESS][1ms], GetValues[SUCCESS, RESPONSE_FROM_CACHE][1ms], TestCommand[FAILURE, FALLBACK_FAILURE][1ms], TestCommand[FAILURE,\n     * FALLBACK_FAILURE, RESPONSE_FROM_CACHE][1ms]</li>\n     * </ul>\n     * <p>\n     * If a command has a multiplier such as <code>x4</code>, that means this command was executed 4 times with the same events. The time in milliseconds is the sum of the 4 executions.\n     * <p>\n     * For example, <code>TestCommand[SUCCESS][15ms]x4</code> represents TestCommand being executed 4 times and the sum of those 4 executions was 15ms. These 4 each executed the run() method since\n     * <code>RESPONSE_FROM_CACHE</code> was not present as an event.\n     *\n     * If an EMIT or FALLBACK_EMIT has a multiplier such as <code>x5</code>, that means a <code>HystrixObservableCommand</code> was used and it emitted that number of <code>OnNext</code>s.\n     * <p>\n     * For example, <code>TestCommand[EMITx5, FAILURE, FALLBACK_EMITx6, FALLBACK_FAILURE][100ms]</code> represents TestCommand executing observably, emitted 5 <code>OnNext</code>s, then an <code>OnError</code>.\n     * This command also has an Observable fallback, and it emits 6 <code>OnNext</code>s, then an <code>OnCompleted</code>.\n     *\n     * @return String request log or \"Unknown\" if unable to instead of throwing an exception.\n     */\n    public String getExecutedCommandsAsString() {\n        try {\n            LinkedHashMap<String, Integer> aggregatedCommandsExecuted = new LinkedHashMap<String, Integer>();\n            Map<String, Integer> aggregatedCommandExecutionTime = new HashMap<String, Integer>();\n\n            StringBuilder builder = new StringBuilder();\n            int estimatedLength = 0;\n            for (HystrixInvokableInfo<?> command : allExecutedCommands) {\n                builder.setLength(0);\n                builder.append(command.getCommandKey().name());\n\n                List<HystrixEventType> events = new ArrayList<HystrixEventType>(command.getExecutionEvents());\n                if (events.size() > 0) {\n                    Collections.sort(events);\n                    //replicate functionality of Arrays.toString(events.toArray()) to append directly to existing StringBuilder\n                    builder.append(\"[\");\n                    for (HystrixEventType event : events) {\n                        switch (event) {\n                            case EMIT:\n                                int numEmissions = command.getNumberEmissions();\n                                if (numEmissions > 1) {\n                                    builder.append(event).append(\"x\").append(numEmissions).append(\", \");\n                                } else {\n                                    builder.append(event).append(\", \");\n                                }\n                                break;\n                            case FALLBACK_EMIT:\n                                int numFallbackEmissions = command.getNumberFallbackEmissions();\n                                if (numFallbackEmissions > 1) {\n                                    builder.append(event).append(\"x\").append(numFallbackEmissions).append(\", \");\n                                } else {\n                                    builder.append(event).append(\", \");\n                                }\n                                break;\n                            default:\n                                builder.append(event).append(\", \");\n                        }\n                    }\n                    builder.setCharAt(builder.length() - 2, ']');\n                    builder.setLength(builder.length() - 1);\n                } else {\n                    builder.append(\"[Executed]\");\n                }\n\n                String display = builder.toString();\n                estimatedLength += display.length() + 12; //add 12 chars to display length for appending totalExecutionTime and count below\n                Integer counter = aggregatedCommandsExecuted.get(display);\n                if( counter != null){\n                    aggregatedCommandsExecuted.put(display, counter + 1);\n                } else {\n                    // add it\n                    aggregatedCommandsExecuted.put(display, 1);\n                }                \n\n                int executionTime = command.getExecutionTimeInMilliseconds();\n                if (executionTime < 0) {\n                    // do this so we don't create negative values or subtract values\n                    executionTime = 0;\n                }\n                counter = aggregatedCommandExecutionTime.get(display);\n                if( counter != null && executionTime > 0){\n                    // add to the existing executionTime (sum of executionTimes for duplicate command displayNames)\n                    aggregatedCommandExecutionTime.put(display, aggregatedCommandExecutionTime.get(display) + executionTime);\n                } else {\n                    // add it\n                    aggregatedCommandExecutionTime.put(display, executionTime);\n                }\n\n            }\n\n            builder.setLength(0);\n            builder.ensureCapacity(estimatedLength);\n            for (String displayString : aggregatedCommandsExecuted.keySet()) {\n                if (builder.length() > 0) {\n                    builder.append(\", \");\n                }\n                builder.append(displayString);\n\n                int totalExecutionTime = aggregatedCommandExecutionTime.get(displayString);\n                builder.append(\"[\").append(totalExecutionTime).append(\"ms]\");\n\n                int count = aggregatedCommandsExecuted.get(displayString);\n                if (count > 1) {\n                    builder.append(\"x\").append(count);\n                }\n            }\n            return builder.toString();\n        } catch (Exception e) {\n            logger.error(\"Failed to create HystrixRequestLog response header string.\", e);\n            // don't let this cause the entire app to fail so just return \"Unknown\"\n            return \"Unknown\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPool.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.Scheduler;\nimport rx.functions.Func0;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * ThreadPool used to executed {@link HystrixCommand#run()} on separate threads when configured to do so with {@link HystrixCommandProperties#executionIsolationStrategy()}.\n * <p>\n * Typically each {@link HystrixCommandGroupKey} has its own thread-pool so that any one group of commands can not starve others from being able to run.\n * <p>\n * A {@link HystrixCommand} can be configured with a thread-pool explicitly by injecting a {@link HystrixThreadPoolKey} or via the\n * {@link HystrixCommandProperties#executionIsolationThreadPoolKeyOverride()} otherwise it\n * will derive a {@link HystrixThreadPoolKey} from the injected {@link HystrixCommandGroupKey}.\n * <p>\n * The pool should be sized large enough to handle normal healthy traffic but small enough that it will constrain concurrent execution if backend calls become latent.\n * <p>\n * For more information see the Github Wiki: https://github.com/Netflix/Hystrix/wiki/Configuration#wiki-ThreadPool and https://github.com/Netflix/Hystrix/wiki/How-it-Works#wiki-Isolation\n */\npublic interface HystrixThreadPool {\n\n    /**\n     * Implementation of {@link ThreadPoolExecutor}.\n     *\n     * @return ThreadPoolExecutor\n     */\n    public ExecutorService getExecutor();\n\n    public Scheduler getScheduler();\n\n    public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread);\n\n    /**\n     * Mark when a thread begins executing a command.\n     */\n    public void markThreadExecution();\n\n    /**\n     * Mark when a thread completes executing a command.\n     */\n    public void markThreadCompletion();\n\n    /**\n     * Mark when a command gets rejected from the threadpool\n     */\n    public void markThreadRejection();\n\n    /**\n     * Whether the queue will allow adding an item to it.\n     * <p>\n     * This allows dynamic control of the max queueSize versus whatever the actual max queueSize is so that dynamic changes can be done via property changes rather than needing an app\n     * restart to adjust when commands should be rejected from queuing up.\n     *\n     * @return boolean whether there is space on the queue\n     */\n    public boolean isQueueSpaceAvailable();\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    /* package */static class Factory {\n        /*\n         * Use the String from HystrixThreadPoolKey.name() instead of the HystrixThreadPoolKey instance as it's just an interface and we can't ensure the object\n         * we receive implements hashcode/equals correctly and do not want the default hashcode/equals which would create a new threadpool for every object we get even if the name is the same\n         */\n        /* package */final static ConcurrentHashMap<String, HystrixThreadPool> threadPools = new ConcurrentHashMap<String, HystrixThreadPool>();\n\n        /**\n         * Get the {@link HystrixThreadPool} instance for a given {@link HystrixThreadPoolKey}.\n         * <p>\n         * This is thread-safe and ensures only 1 {@link HystrixThreadPool} per {@link HystrixThreadPoolKey}.\n         *\n         * @return {@link HystrixThreadPool} instance\n         */\n        /* package */static HystrixThreadPool getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesBuilder) {\n            // get the key to use instead of using the object itself so that if people forget to implement equals/hashcode things will still work\n            String key = threadPoolKey.name();\n\n            // this should find it for all but the first time\n            HystrixThreadPool previouslyCached = threadPools.get(key);\n            if (previouslyCached != null) {\n                return previouslyCached;\n            }\n\n            // if we get here this is the first time so we need to initialize\n            synchronized (HystrixThreadPool.class) {\n                if (!threadPools.containsKey(key)) {\n                    threadPools.put(key, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));\n                }\n            }\n            return threadPools.get(key);\n        }\n\n        /**\n         * Initiate the shutdown of all {@link HystrixThreadPool} instances.\n         * <p>\n         * NOTE: This is NOT thread-safe if HystrixCommands are concurrently being executed\n         * and causing thread-pools to initialize while also trying to shutdown.\n         * </p>\n         */\n        /* package */static synchronized void shutdown() {\n            for (HystrixThreadPool pool : threadPools.values()) {\n                pool.getExecutor().shutdown();\n            }\n            threadPools.clear();\n        }\n\n        /**\n         * Initiate the shutdown of all {@link HystrixThreadPool} instances and wait up to the given time on each pool to complete.\n         * <p>\n         * NOTE: This is NOT thread-safe if HystrixCommands are concurrently being executed\n         * and causing thread-pools to initialize while also trying to shutdown.\n         * </p>\n         */\n        /* package */static synchronized void shutdown(long timeout, TimeUnit unit) {\n            for (HystrixThreadPool pool : threadPools.values()) {\n                pool.getExecutor().shutdown();\n            }\n            for (HystrixThreadPool pool : threadPools.values()) {\n                try {\n                    while (! pool.getExecutor().awaitTermination(timeout, unit)) {\n                    }\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(\"Interrupted while waiting for thread-pools to terminate. Pools may not be correctly shutdown or cleared.\", e);\n                }\n            }\n            threadPools.clear();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     * @ThreadSafe\n     */\n    /* package */static class HystrixThreadPoolDefault implements HystrixThreadPool {\n        private static final Logger logger = LoggerFactory.getLogger(HystrixThreadPoolDefault.class);\n\n        private final HystrixThreadPoolProperties properties;\n        private final BlockingQueue<Runnable> queue;\n        private final ThreadPoolExecutor threadPool;\n        private final HystrixThreadPoolMetrics metrics;\n        private final int queueSize;\n\n        public HystrixThreadPoolDefault(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesDefaults) {\n            this.properties = HystrixPropertiesFactory.getThreadPoolProperties(threadPoolKey, propertiesDefaults);\n            HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();\n            this.queueSize = properties.maxQueueSize().get();\n\n            this.metrics = HystrixThreadPoolMetrics.getInstance(threadPoolKey,\n                    concurrencyStrategy.getThreadPool(threadPoolKey, properties),\n                    properties);\n            this.threadPool = this.metrics.getThreadPool();\n            this.queue = this.threadPool.getQueue();\n\n            /* strategy: HystrixMetricsPublisherThreadPool */\n            HystrixMetricsPublisherFactory.createOrRetrievePublisherForThreadPool(threadPoolKey, this.metrics, this.properties);\n        }\n\n        @Override\n        public ThreadPoolExecutor getExecutor() {\n            touchConfig();\n            return threadPool;\n        }\n\n        @Override\n        public Scheduler getScheduler() {\n            //by default, interrupt underlying threads on timeout\n            return getScheduler(new Func0<Boolean>() {\n                @Override\n                public Boolean call() {\n                    return true;\n                }\n            });\n        }\n\n        @Override\n        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n            touchConfig();\n            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n        }\n\n        // allow us to change things via fast-properties by setting it each time\n        private void touchConfig() {\n            final int dynamicCoreSize = properties.coreSize().get();\n            final int configuredMaximumSize = properties.maximumSize().get();\n            int dynamicMaximumSize = properties.actualMaximumSize();\n            final boolean allowSizesToDiverge = properties.getAllowMaximumSizeToDivergeFromCoreSize().get();\n            boolean maxTooLow = false;\n\n            if (allowSizesToDiverge && configuredMaximumSize < dynamicCoreSize) {\n                //if user sets maximum < core (or defaults get us there), we need to maintain invariant of core <= maximum\n                dynamicMaximumSize = dynamicCoreSize;\n                maxTooLow = true;\n            }\n\n            // In JDK 6, setCorePoolSize and setMaximumPoolSize will execute a lock operation. Avoid them if the pool size is not changed.\n            if (threadPool.getCorePoolSize() != dynamicCoreSize || (allowSizesToDiverge && threadPool.getMaximumPoolSize() != dynamicMaximumSize)) {\n                if (maxTooLow) {\n                    logger.error(\"Hystrix ThreadPool configuration for : \" + metrics.getThreadPoolKey().name() + \" is trying to set coreSize = \" +\n                            dynamicCoreSize + \" and maximumSize = \" + configuredMaximumSize + \".  Maximum size will be set to \" +\n                            dynamicMaximumSize + \", the coreSize value, since it must be equal to or greater than the coreSize value\");\n                }\n                threadPool.setCorePoolSize(dynamicCoreSize);\n                threadPool.setMaximumPoolSize(dynamicMaximumSize);\n            }\n\n            threadPool.setKeepAliveTime(properties.keepAliveTimeMinutes().get(), TimeUnit.MINUTES);\n        }\n\n        @Override\n        public void markThreadExecution() {\n            metrics.markThreadExecution();\n        }\n\n        @Override\n        public void markThreadCompletion() {\n            metrics.markThreadCompletion();\n        }\n\n        @Override\n        public void markThreadRejection() {\n            metrics.markThreadRejection();\n        }\n\n        /**\n         * Whether the threadpool queue has space available according to the <code>queueSizeRejectionThreshold</code> settings.\n         *\n         * Note that the <code>queueSize</code> is an final instance variable on HystrixThreadPoolDefault, and not looked up dynamically.\n         * The data structure is static, so this does not make sense as a dynamic lookup.\n         * The <code>queueSizeRejectionThreshold</code> can be dynamic (up to <code>queueSize</code>), so that should\n         * still get checked on each invocation.\n         * <p>\n         * If a SynchronousQueue implementation is used (<code>maxQueueSize</code> <= 0), it always returns 0 as the size so this would always return true.\n         */\n        @Override\n        public boolean isQueueSpaceAvailable() {\n            if (queueSize <= 0) {\n                // we don't have a queue so we won't look for space but instead\n                // let the thread-pool reject or not\n                return true;\n            } else {\n                return threadPool.getQueue().size() < properties.queueSizeRejectionThreshold().get();\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.util.InternMap;\n\n/**\n * A key to represent a {@link HystrixThreadPool} for monitoring, metrics publishing, caching and other such uses.\n * <p>\n * This interface is intended to work natively with Enums so that implementing code can be an enum that implements this interface.\n */\npublic interface HystrixThreadPoolKey extends HystrixKey {\n    class Factory {\n        private Factory() {\n        }\n\n        // used to intern instances so we don't keep re-creating them millions of times for the same key\n        private static final InternMap<String, HystrixThreadPoolKey> intern\n                = new InternMap<String, HystrixThreadPoolKey>(\n                new InternMap.ValueConstructor<String, HystrixThreadPoolKey>() {\n                    @Override\n                    public HystrixThreadPoolKey create(String key) {\n                        return new HystrixThreadPoolKeyDefault(key);\n                    }\n                });\n\n        /**\n         * Retrieve (or create) an interned HystrixThreadPoolKey instance for a given name.\n         * \n         * @param name thread pool name\n         * @return HystrixThreadPoolKey instance that is interned (cached) so a given name will always retrieve the same instance.\n         */\n        public static HystrixThreadPoolKey asKey(String name) {\n           return intern.interned(name);\n        }\n\n        private static class HystrixThreadPoolKeyDefault extends HystrixKeyDefault implements HystrixThreadPoolKey {\n            public HystrixThreadPoolKeyDefault(String name) {\n                super(name);\n            }\n        }\n\n        /* package-private */ static int getThreadPoolCount() {\n            return intern.size();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolMetrics.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.consumer.CumulativeThreadPoolEventCounterStream;\nimport com.netflix.hystrix.metric.consumer.RollingThreadPoolMaxConcurrencyStream;\nimport com.netflix.hystrix.metric.consumer.RollingThreadPoolEventCounterStream;\nimport com.netflix.hystrix.util.HystrixRollingNumberEvent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\nimport rx.functions.Func2;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Used by {@link HystrixThreadPool} to record metrics.\n */\npublic class HystrixThreadPoolMetrics extends HystrixMetrics {\n\n    private static final HystrixEventType[] ALL_COMMAND_EVENT_TYPES = HystrixEventType.values();\n    private static final HystrixEventType.ThreadPool[] ALL_THREADPOOL_EVENT_TYPES = HystrixEventType.ThreadPool.values();\n    private static final int NUMBER_THREADPOOL_EVENT_TYPES = ALL_THREADPOOL_EVENT_TYPES.length;\n\n    // String is HystrixThreadPoolKey.name() (we can't use HystrixThreadPoolKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixThreadPoolMetrics> metrics = new ConcurrentHashMap<String, HystrixThreadPoolMetrics>();\n\n    /**\n     * Get or create the {@link HystrixThreadPoolMetrics} instance for a given {@link HystrixThreadPoolKey}.\n     * <p>\n     * This is thread-safe and ensures only 1 {@link HystrixThreadPoolMetrics} per {@link HystrixThreadPoolKey}.\n     * \n     * @param key\n     *            {@link HystrixThreadPoolKey} of {@link HystrixThreadPool} instance requesting the {@link HystrixThreadPoolMetrics}\n     * @param threadPool\n     *            Pass-thru of ThreadPoolExecutor to {@link HystrixThreadPoolMetrics} instance on first time when constructed\n     * @param properties\n     *            Pass-thru to {@link HystrixThreadPoolMetrics} instance on first time when constructed\n     * @return {@link HystrixThreadPoolMetrics}\n     */\n    public static HystrixThreadPoolMetrics getInstance(HystrixThreadPoolKey key, ThreadPoolExecutor threadPool, HystrixThreadPoolProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixThreadPoolMetrics threadPoolMetrics = metrics.get(key.name());\n        if (threadPoolMetrics != null) {\n            return threadPoolMetrics;\n        } else {\n            synchronized (HystrixThreadPoolMetrics.class) {\n                HystrixThreadPoolMetrics existingMetrics = metrics.get(key.name());\n                if (existingMetrics != null) {\n                    return existingMetrics;\n                } else {\n                    HystrixThreadPoolMetrics newThreadPoolMetrics = new HystrixThreadPoolMetrics(key, threadPool, properties);\n                    metrics.putIfAbsent(key.name(), newThreadPoolMetrics);\n                    return newThreadPoolMetrics;\n                }\n            }\n        }\n    }\n\n    /**\n     * Get the {@link HystrixThreadPoolMetrics} instance for a given {@link HystrixThreadPoolKey} or null if one does not exist.\n     * \n     * @param key\n     *            {@link HystrixThreadPoolKey} of {@link HystrixThreadPool} instance requesting the {@link HystrixThreadPoolMetrics}\n     * @return {@link HystrixThreadPoolMetrics}\n     */\n    public static HystrixThreadPoolMetrics getInstance(HystrixThreadPoolKey key) {\n        return metrics.get(key.name());\n    }\n\n    /**\n     * All registered instances of {@link HystrixThreadPoolMetrics}\n     * \n     * @return {@code Collection<HystrixThreadPoolMetrics>}\n     */\n    public static Collection<HystrixThreadPoolMetrics> getInstances() {\n        List<HystrixThreadPoolMetrics> threadPoolMetrics = new ArrayList<HystrixThreadPoolMetrics>();\n        for (HystrixThreadPoolMetrics tpm: metrics.values()) {\n            if (hasExecutedCommandsOnThread(tpm)) {\n                threadPoolMetrics.add(tpm);\n            }\n        }\n\n        return Collections.unmodifiableCollection(threadPoolMetrics);\n    }\n\n    private static boolean hasExecutedCommandsOnThread(HystrixThreadPoolMetrics threadPoolMetrics) {\n        return threadPoolMetrics.getCurrentCompletedTaskCount().intValue() > 0;\n    }\n\n    public static final Func2<long[], HystrixCommandCompletion, long[]> appendEventToBucket\n            = new Func2<long[], HystrixCommandCompletion, long[]>() {\n        @Override\n        public long[] call(long[] initialCountArray, HystrixCommandCompletion execution) {\n            ExecutionResult.EventCounts eventCounts = execution.getEventCounts();\n            for (HystrixEventType eventType: ALL_COMMAND_EVENT_TYPES) {\n                long eventCount = eventCounts.getCount(eventType);\n                HystrixEventType.ThreadPool threadPoolEventType = HystrixEventType.ThreadPool.from(eventType);\n                if (threadPoolEventType != null) {\n                    initialCountArray[threadPoolEventType.ordinal()] += eventCount;\n                }\n            }\n            return initialCountArray;\n        }\n    };\n\n    public static final Func2<long[], long[], long[]> counterAggregator = new Func2<long[], long[], long[]>() {\n        @Override\n        public long[] call(long[] cumulativeEvents, long[] bucketEventCounts) {\n            for (int i = 0; i < NUMBER_THREADPOOL_EVENT_TYPES; i++) {\n                cumulativeEvents[i] += bucketEventCounts[i];\n            }\n            return cumulativeEvents;\n        }\n    };\n\n    /**\n     * Clears all state from metrics. If new requests come in instances will be recreated and metrics started from scratch.\n     *\n     */\n    /* package */ static void reset() {\n        metrics.clear();\n    }\n\n    private final HystrixThreadPoolKey threadPoolKey;\n    private final ThreadPoolExecutor threadPool;\n    private final HystrixThreadPoolProperties properties;\n\n    private final AtomicInteger concurrentExecutionCount = new AtomicInteger();\n\n    private final RollingThreadPoolEventCounterStream rollingCounterStream;\n    private final CumulativeThreadPoolEventCounterStream cumulativeCounterStream;\n    private final RollingThreadPoolMaxConcurrencyStream rollingThreadPoolMaxConcurrencyStream;\n\n    private HystrixThreadPoolMetrics(HystrixThreadPoolKey threadPoolKey, ThreadPoolExecutor threadPool, HystrixThreadPoolProperties properties) {\n        super(null);\n        this.threadPoolKey = threadPoolKey;\n        this.threadPool = threadPool;\n        this.properties = properties;\n\n        rollingCounterStream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, properties);\n        cumulativeCounterStream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, properties);\n        rollingThreadPoolMaxConcurrencyStream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, properties);\n    }\n\n    /**\n     * {@link ThreadPoolExecutor} this executor represents.\n     *\n     * @return ThreadPoolExecutor\n     */\n    public ThreadPoolExecutor getThreadPool() {\n        return threadPool;\n    }\n\n    /**\n     * {@link HystrixThreadPoolKey} these metrics represent.\n     * \n     * @return HystrixThreadPoolKey\n     */\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    /**\n     * {@link HystrixThreadPoolProperties} of the {@link HystrixThreadPool} these metrics represent.\n     * \n     * @return HystrixThreadPoolProperties\n     */\n    public HystrixThreadPoolProperties getProperties() {\n        return properties;\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getActiveCount()}\n     * \n     * @return Number\n     */\n    public Number getCurrentActiveCount() {\n        return threadPool.getActiveCount();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getCompletedTaskCount()}\n     * \n     * @return Number\n     */\n    public Number getCurrentCompletedTaskCount() {\n        return threadPool.getCompletedTaskCount();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getCorePoolSize()}\n     * \n     * @return Number\n     */\n    public Number getCurrentCorePoolSize() {\n        return threadPool.getCorePoolSize();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getLargestPoolSize()}\n     * \n     * @return Number\n     */\n    public Number getCurrentLargestPoolSize() {\n        return threadPool.getLargestPoolSize();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getMaximumPoolSize()}\n     * \n     * @return Number\n     */\n    public Number getCurrentMaximumPoolSize() {\n        return threadPool.getMaximumPoolSize();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getPoolSize()}\n     * \n     * @return Number\n     */\n    public Number getCurrentPoolSize() {\n        return threadPool.getPoolSize();\n    }\n\n    /**\n     * Value from {@link ThreadPoolExecutor#getTaskCount()}\n     * \n     * @return Number\n     */\n    public Number getCurrentTaskCount() {\n        return threadPool.getTaskCount();\n    }\n\n    /**\n     * Current size of {@link BlockingQueue} used by the thread-pool\n     * \n     * @return Number\n     */\n    public Number getCurrentQueueSize() {\n        return threadPool.getQueue().size();\n    }\n\n    /**\n     * Invoked each time a thread is executed.\n     */\n    public void markThreadExecution() {\n        concurrentExecutionCount.incrementAndGet();\n    }\n\n    /**\n     * Rolling count of number of threads executed during rolling statistical window.\n     * <p>\n     * The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.\n     *\n     * @return rolling count of threads executed\n     */\n    public long getRollingCountThreadsExecuted() {\n        return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED);\n    }\n\n    /**\n     * Cumulative count of number of threads executed since the start of the application.\n     * \n     * @return cumulative count of threads executed\n     */\n    public long getCumulativeCountThreadsExecuted() {\n        return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED);\n    }\n\n    /**\n     * Rolling count of number of threads rejected during rolling statistical window.\n     * <p>\n     * The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.\n     *\n     * @return rolling count of threads rejected\n     */\n    public long getRollingCountThreadsRejected() {\n        return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.REJECTED);\n    }\n\n    /**\n     * Cumulative count of number of threads rejected since the start of the application.\n     *\n     * @return cumulative count of threads rejected\n     */\n    public long getCumulativeCountThreadsRejected() {\n        return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.REJECTED);\n    }\n\n    public long getRollingCount(HystrixEventType.ThreadPool event) {\n        return rollingCounterStream.getLatestCount(event);\n    }\n\n    public long getCumulativeCount(HystrixEventType.ThreadPool event) {\n        return cumulativeCounterStream.getLatestCount(event);\n    }\n\n    @Override\n    public long getCumulativeCount(HystrixRollingNumberEvent event) {\n        return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.from(event));\n    }\n\n    @Override\n    public long getRollingCount(HystrixRollingNumberEvent event) {\n        return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.from(event));\n    }\n\n    /**\n     * Invoked each time a thread completes.\n     */\n    public void markThreadCompletion() {\n        concurrentExecutionCount.decrementAndGet();\n    }\n\n    /**\n     * Rolling max number of active threads during rolling statistical window.\n     * <p>\n     * The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.\n     * \n     * @return rolling max active threads\n     */\n    public long getRollingMaxActiveThreads() {\n        return rollingThreadPoolMaxConcurrencyStream.getLatestRollingMax();\n    }\n\n    /**\n     * Invoked each time a command is rejected from the thread-pool\n     */\n    public void markThreadRejection() {\n        concurrentExecutionCount.decrementAndGet();\n    }\n\n    public static Func0<Integer> getCurrentConcurrencyThunk(final HystrixThreadPoolKey threadPoolKey) {\n        return new Func0<Integer>() {\n            @Override\n            public Integer call() {\n                return HystrixThreadPoolMetrics.getInstance(threadPoolKey).concurrentExecutionCount.get();\n            }\n        };\n    }\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixThreadPoolProperties.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean;\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixRollingNumber;\n\n/**\n * Properties for instances of {@link HystrixThreadPool}.\n * <p>\n * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)\n *\n * Note a change in behavior in 1.5.7.  Prior to that version, the configuration for 'coreSize' was used to control\n * both coreSize and maximumSize.  This is a fixed-size threadpool that can never give up an unused thread.  In 1.5.7+,\n * the values can diverge, and if you set coreSize < maximumSize, threads can be given up (subject to the keep-alive\n * time)\n *\n * It is OK to leave maximumSize unset using any version of Hystrix.  If you do, then maximum size will default to\n * core size and you'll have a fixed-size threadpool.\n *\n * If you accidentally set maximumSize < coreSize, then maximum will be raised to coreSize\n * (this prioritizes keeping extra threads around rather than inducing threadpool rejections)\n */\npublic abstract class HystrixThreadPoolProperties {\n\n    /* defaults */\n    static int default_coreSize = 10;            // core size of thread pool\n    static int default_maximumSize = 10;         // maximum size of thread pool\n    static int default_keepAliveTimeMinutes = 1; // minutes to keep a thread alive\n    static int default_maxQueueSize = -1;        // size of queue (this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject)\n                                                 // -1 turns it off and makes us use SynchronousQueue\n    static boolean default_allow_maximum_size_to_diverge_from_core_size = false; //should the maximumSize config value get read and used in configuring the threadPool\n                                                                                 //turning this on should be a conscious decision by the user, so we default it to false\n\n    static int default_queueSizeRejectionThreshold = 5; // number of items in queue\n    static int default_threadPoolRollingNumberStatisticalWindow = 10000; // milliseconds for rolling number\n    static int default_threadPoolRollingNumberStatisticalWindowBuckets = 10; // number of buckets in rolling number (10 1-second buckets)\n\n    private final HystrixProperty<Integer> corePoolSize;\n    private final HystrixProperty<Integer> maximumPoolSize;\n    private final HystrixProperty<Integer> keepAliveTime;\n    private final HystrixProperty<Integer> maxQueueSize;\n    private final HystrixProperty<Integer> queueSizeRejectionThreshold;\n    private final HystrixProperty<Boolean> allowMaximumSizeToDivergeFromCoreSize;\n\n    private final HystrixProperty<Integer> threadPoolRollingNumberStatisticalWindowInMilliseconds;\n    private final HystrixProperty<Integer> threadPoolRollingNumberStatisticalWindowBuckets;\n\n    protected HystrixThreadPoolProperties(HystrixThreadPoolKey key) {\n        this(key, new Setter(), \"hystrix\");\n    }\n\n    protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder) {\n        this(key, builder, \"hystrix\");\n    }\n\n    protected HystrixThreadPoolProperties(HystrixThreadPoolKey key, Setter builder, String propertyPrefix) {\n        this.allowMaximumSizeToDivergeFromCoreSize = getProperty(propertyPrefix, key, \"allowMaximumSizeToDivergeFromCoreSize\",\n                builder.getAllowMaximumSizeToDivergeFromCoreSize(), default_allow_maximum_size_to_diverge_from_core_size);\n\n        this.corePoolSize = getProperty(propertyPrefix, key, \"coreSize\", builder.getCoreSize(), default_coreSize);\n        //this object always contains a reference to the configuration value for the maximumSize of the threadpool\n        //it only gets applied if allowMaximumSizeToDivergeFromCoreSize is true\n        this.maximumPoolSize = getProperty(propertyPrefix, key, \"maximumSize\", builder.getMaximumSize(), default_maximumSize);\n\n        this.keepAliveTime = getProperty(propertyPrefix, key, \"keepAliveTimeMinutes\", builder.getKeepAliveTimeMinutes(), default_keepAliveTimeMinutes);\n        this.maxQueueSize = getProperty(propertyPrefix, key, \"maxQueueSize\", builder.getMaxQueueSize(), default_maxQueueSize);\n        this.queueSizeRejectionThreshold = getProperty(propertyPrefix, key, \"queueSizeRejectionThreshold\", builder.getQueueSizeRejectionThreshold(), default_queueSizeRejectionThreshold);\n        this.threadPoolRollingNumberStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, \"metrics.rollingStats.timeInMilliseconds\", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_threadPoolRollingNumberStatisticalWindow);\n        this.threadPoolRollingNumberStatisticalWindowBuckets = getProperty(propertyPrefix, key, \"metrics.rollingStats.numBuckets\", builder.getMetricsRollingStatisticalWindowBuckets(), default_threadPoolRollingNumberStatisticalWindowBuckets);\n    }\n\n    private static HystrixProperty<Integer> getProperty(String propertyPrefix, HystrixThreadPoolKey key, String instanceProperty, Integer builderOverrideValue, Integer defaultValue) {\n        return forInteger()\n                .add(propertyPrefix + \".threadpool.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".threadpool.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    private static HystrixProperty<Boolean> getProperty(String propertyPrefix, HystrixThreadPoolKey key, String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) {\n        return forBoolean()\n                .add(propertyPrefix + \".threadpool.\" + key.name() + \".\" + instanceProperty, builderOverrideValue)\n                .add(propertyPrefix + \".threadpool.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    /**\n     * Core thread-pool size that gets passed to {@link ThreadPoolExecutor#setCorePoolSize(int)}\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> coreSize() {\n        return corePoolSize;\n    }\n\n    /**\n     * Maximum thread-pool size configured for threadpool.  May conflict with other config, so if you need the\n     * actual value that gets passed to {@link ThreadPoolExecutor#setMaximumPoolSize(int)}, use {@link #actualMaximumSize()}\n     *\n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> maximumSize() {\n        return maximumPoolSize;\n    }\n\n    /**\n     * Given all of the thread pool configuration, what is the actual maximumSize applied to the thread pool\n     * via {@link ThreadPoolExecutor#setMaximumPoolSize(int)}\n     *\n     * Cases:\n     * 1) allowMaximumSizeToDivergeFromCoreSize == false: maximumSize is set to coreSize\n     * 2) allowMaximumSizeToDivergeFromCoreSize == true, maximumSize >= coreSize: thread pool has different core/max sizes, so return the configured max\n     * 3) allowMaximumSizeToDivergeFromCoreSize == true, maximumSize < coreSize: threadpool incorrectly configured, use coreSize for max size\n     * @return actually configured maximum size of threadpool\n     */\n    public Integer actualMaximumSize() {\n        final int coreSize = coreSize().get();\n        final int maximumSize = maximumSize().get();\n        if (getAllowMaximumSizeToDivergeFromCoreSize().get()) {\n            if (coreSize > maximumSize) {\n                return coreSize;\n            } else {\n                return maximumSize;\n            }\n        } else {\n            return coreSize;\n        }\n    }\n\n    /**\n     * Keep-alive time in minutes that gets passed to {@link ThreadPoolExecutor#setKeepAliveTime(long, TimeUnit)}\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> keepAliveTimeMinutes() {\n        return keepAliveTime;\n    }\n\n    /**\n     * Max queue size that gets passed to {@link BlockingQueue} in {@link HystrixConcurrencyStrategy#getBlockingQueue(int)}\n     *\n     * This should only affect the instantiation of a threadpool - it is not eliglible to change a queue size on the fly.\n     * For that, use {@link #queueSizeRejectionThreshold()}.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> maxQueueSize() {\n        return maxQueueSize;\n    }\n\n    /**\n     * Queue size rejection threshold is an artificial \"max\" size at which rejections will occur even if {@link #maxQueueSize} has not been reached. This is done because the {@link #maxQueueSize} of a\n     * {@link BlockingQueue} can not be dynamically changed and we want to support dynamically changing the queue size that affects rejections.\n     * <p>\n     * This is used by {@link HystrixCommand} when queuing a thread for execution.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> queueSizeRejectionThreshold() {\n        return queueSizeRejectionThreshold;\n    }\n\n    public HystrixProperty<Boolean> getAllowMaximumSizeToDivergeFromCoreSize() {\n        return allowMaximumSizeToDivergeFromCoreSize;\n    }\n\n    /**\n     * Duration of statistical rolling window in milliseconds. This is passed into {@link HystrixRollingNumber} inside each {@link HystrixThreadPoolMetrics} instance.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds() {\n        return threadPoolRollingNumberStatisticalWindowInMilliseconds;\n    }\n\n    /**\n     * Number of buckets the rolling statistical window is broken into. This is passed into {@link HystrixRollingNumber} inside each {@link HystrixThreadPoolMetrics} instance.\n     * \n     * @return {@code HystrixProperty<Integer>}\n     */\n    public HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets() {\n        return threadPoolRollingNumberStatisticalWindowBuckets;\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     */\n    public static Setter Setter() {\n        return new Setter();\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     * Groovy has a bug (GROOVY-6286) which does not allow method names and inner classes to have the same name\n     * This method fixes Issue #967 and allows Groovy consumers to choose this method and not trigger the bug\n     */\n    public static Setter defaultSetter() {\n        return Setter();\n    }\n\n    /**\n     * Fluent interface that allows chained setting of properties that can be passed into a {@link HystrixThreadPool} via a {@link HystrixCommand} constructor to inject instance specific property\n     * overrides.\n     * <p>\n     * See {@link HystrixPropertiesStrategy} for more information on order of precedence.\n     * <p>\n     * Example:\n     * <p>\n     * <pre> {@code\n     * HystrixThreadPoolProperties.Setter()\n     *           .withCoreSize(10)\n     *           .withQueueSizeRejectionThreshold(10);\n     * } </pre>\n     * \n     * @NotThreadSafe\n     */\n    public static class Setter {\n        private Integer coreSize = null;\n        private Integer maximumSize = null;\n        private Integer keepAliveTimeMinutes = null;\n        private Integer maxQueueSize = null;\n        private Integer queueSizeRejectionThreshold = null;\n        private Boolean allowMaximumSizeToDivergeFromCoreSize = null;\n        private Integer rollingStatisticalWindowInMilliseconds = null;\n        private Integer rollingStatisticalWindowBuckets = null;\n\n        private Setter() {\n        }\n\n        public Integer getCoreSize() {\n            return coreSize;\n        }\n\n        public Integer getMaximumSize() {\n            return maximumSize;\n        }\n\n        public Integer getKeepAliveTimeMinutes() {\n            return keepAliveTimeMinutes;\n        }\n\n        public Integer getMaxQueueSize() {\n            return maxQueueSize;\n        }\n\n        public Integer getQueueSizeRejectionThreshold() {\n            return queueSizeRejectionThreshold;\n        }\n\n        public Boolean getAllowMaximumSizeToDivergeFromCoreSize() {\n            return allowMaximumSizeToDivergeFromCoreSize;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowInMilliseconds() {\n            return rollingStatisticalWindowInMilliseconds;\n        }\n\n        public Integer getMetricsRollingStatisticalWindowBuckets() {\n            return rollingStatisticalWindowBuckets;\n        }\n\n        public Setter withCoreSize(int value) {\n            this.coreSize = value;\n            return this;\n        }\n\n        public Setter withMaximumSize(int value) {\n            this.maximumSize = value;\n            return this;\n        }\n\n        public Setter withKeepAliveTimeMinutes(int value) {\n            this.keepAliveTimeMinutes = value;\n            return this;\n        }\n\n        public Setter withMaxQueueSize(int value) {\n            this.maxQueueSize = value;\n            return this;\n        }\n\n        public Setter withQueueSizeRejectionThreshold(int value) {\n            this.queueSizeRejectionThreshold = value;\n            return this;\n        }\n\n        public Setter withAllowMaximumSizeToDivergeFromCoreSize(boolean value) {\n            this.allowMaximumSizeToDivergeFromCoreSize = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowInMilliseconds(int value) {\n            this.rollingStatisticalWindowInMilliseconds = value;\n            return this;\n        }\n\n        public Setter withMetricsRollingStatisticalWindowBuckets(int value) {\n            this.rollingStatisticalWindowBuckets = value;\n            return this;\n        }\n\n\n\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/HystrixTimerThreadPoolProperties.java",
    "content": "package com.netflix.hystrix;\n\nimport static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger;\n\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\n\n/**\n * Properties for Hystrix timer thread pool.\n * <p>\n * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)\n */\npublic abstract class HystrixTimerThreadPoolProperties {\n\n    private final HystrixProperty<Integer> corePoolSize;\n\n    protected HystrixTimerThreadPoolProperties() {\n        this(new Setter().withCoreSize(Runtime.getRuntime().availableProcessors()));\n    }\n\n    protected HystrixTimerThreadPoolProperties(Setter setter) {\n        this.corePoolSize = getProperty(\"hystrix\", \"coreSize\", setter.getCoreSize());\n    }\n\n    private static HystrixProperty<Integer> getProperty(String propertyPrefix, String instanceProperty, Integer defaultValue) {\n        \n        return forInteger()\n                .add(propertyPrefix + \".timer.threadpool.default.\" + instanceProperty, defaultValue)\n                .build();\n    }\n\n    public HystrixProperty<Integer> getCorePoolSize() {\n        return corePoolSize;\n    }\n\n    /**\n     * Factory method to retrieve the default Setter.\n     */\n    public static Setter Setter() {\n        return new Setter();\n    }\n\n    /**\n     * Fluent interface that allows chained setting of properties.\n     * <p>\n     * See {@link HystrixPropertiesStrategy} for more information on order of precedence.\n     * <p>\n     * Example:\n     * <p>\n     * <pre> {@code\n     * HystrixTimerThreadPoolProperties.Setter()\n     *           .withCoreSize(10);\n     * } </pre>\n     *\n     * @NotThreadSafe\n     */\n    public static class Setter {\n        private Integer coreSize = null;\n\n        private Setter() {\n        }\n\n        public Integer getCoreSize() {\n            return coreSize;\n        }\n\n        public Setter withCoreSize(int value) {\n            this.coreSize = value;\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/CollapsedRequestSubject.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.subjects.ReplaySubject;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * The Observable that represents a collapsed request sent back to a user.  It gets used by Collapser implementations\n * when receiving a batch response and emitting values/errors to collapsers.\n *\n * There are 4 methods that Collapser implementations may use:\n *\n * 1) {@link #setResponse(T)}: return a single-valued response.  equivalent to OnNext(T), OnCompleted()\n * 2) {@link #emitResponse(T)}: emit a single value.  equivalent to OnNext(T)\n * 3) {@link #setException(Exception)}: return an exception.  equivalent to OnError(Exception)\n * 4) {@link #setComplete()}: mark that no more values will be emitted.  Should be used in conjunction with {@link #emitResponse(T)}.  equivalent to OnCompleted()\n *\n * <p>\n * This is an internal implementation of CollapsedRequest<T, R> functionality.  Instead of directly extending {@link rx.Observable},\n * it provides a {@link #toObservable()} method\n * <p>\n *\n * @param <T>\n * \n * @param <R>\n */\n/* package */class CollapsedRequestSubject<T, R> implements CollapsedRequest<T, R> {\n    private final R argument;\n\n    private AtomicBoolean valueSet = new AtomicBoolean(false);\n    private final ReplaySubject<T> subject = ReplaySubject.create();\n    private final Observable<T> subjectWithAccounting;\n\n    private volatile int outstandingSubscriptions = 0;\n\n    public CollapsedRequestSubject(final R arg, final RequestBatch<?, T, R> containingBatch) {\n        if (arg == RequestCollapser.NULL_SENTINEL) {\n            this.argument = null;\n        } else {\n            this.argument = arg;\n        }\n        this.subjectWithAccounting = subject\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        outstandingSubscriptions++;\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        outstandingSubscriptions--;\n                        if (outstandingSubscriptions == 0) {\n                            containingBatch.remove(arg);\n                        }\n                    }\n                });\n    }\n\n    public CollapsedRequestSubject(final R arg) {\n        this.subjectWithAccounting = subject;\n        this.argument = arg;\n    }\n\n    /**\n     * The request argument.\n     * \n     * @return request argument\n     */\n    @Override\n    public R getArgument() {\n        return argument;\n    }\n\n    /**\n     * When set any client thread blocking on get() will immediately be unblocked and receive the single-valued response.\n     * \n     * @throws IllegalStateException\n     *             if called more than once or after setException.\n     * @param response response to give to initial command\n     */\n    @Override\n    public void setResponse(T response) {\n        if (!isTerminated()) {\n            subject.onNext(response);\n            valueSet.set(true);\n            subject.onCompleted();\n        } else {\n            throw new IllegalStateException(\"Response has already terminated so response can not be set : \" + response);\n        }\n    }\n\n    /**\n     * Emit a response that should be OnNexted to an Observer\n     * @param response response to emit to initial command\n     */\n    @Override\n    public void emitResponse(T response) {\n        if (!isTerminated()) {\n            subject.onNext(response);\n            valueSet.set(true);\n        } else {\n            throw new IllegalStateException(\"Response has already terminated so response can not be set : \" + response);\n        }\n    }\n\n    @Override\n    public void setComplete() {\n        if (!isTerminated()) {\n            subject.onCompleted();\n        }\n    }\n\n    /**\n     * Set an exception if a response is not yet received otherwise skip it\n     * \n     * @param e synthetic error to set on initial command when no actual response is available\n     */\n    public void setExceptionIfResponseNotReceived(Exception e) {\n        if (!valueSet.get() && !isTerminated()) {\n            subject.onError(e);\n        }\n    }\n\n    /**\n     * Set an ISE if a response is not yet received otherwise skip it\n     *\n     * @param e A pre-generated exception.  If this is null an ISE will be created and returned\n     * @param exceptionMessage The message for the ISE\n     */\n    public Exception setExceptionIfResponseNotReceived(Exception e, String exceptionMessage) {\n        Exception exception = e;\n\n        if (!valueSet.get() && !isTerminated()) {\n            if (e == null) {\n                exception = new IllegalStateException(exceptionMessage);\n            }\n            setExceptionIfResponseNotReceived(exception);\n        }\n        // return any exception that was generated\n        return exception;\n    }\n\n    /**\n     * When set any client thread blocking on get() will immediately be unblocked and receive the exception.\n     * \n     * @throws IllegalStateException\n     *             if called more than once or after setResponse.\n     * @param e received exception that gets set on the initial command\n     */\n    @Override\n    public void setException(Exception e) {\n        if (!isTerminated()) {\n            subject.onError(e);\n        } else {\n            throw new IllegalStateException(\"Response has already terminated so exception can not be set\", e);\n        }\n    }\n\n    private boolean isTerminated() {\n        return (subject.hasCompleted() || subject.hasThrowable());\n    }\n\n    public Observable<T> toObservable() {\n        return subjectWithAccounting;\n    }\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/CollapserTimer.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.lang.ref.Reference;\n\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\n\n/**\n * Timer used for trigger batch execution.\n */\npublic interface CollapserTimer {\n\n    public Reference<TimerListener> addListener(TimerListener collapseTask);\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/HystrixCollapserBridge.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.util.Collection;\n\nimport rx.Observable;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.HystrixCollapserKey;\n\n/**\n * Bridge between HystrixCollapser and RequestCollapser to expose 'protected' and 'private' functionality across packages.\n * \n * @param <BatchReturnType>\n * @param <ResponseType>\n * @param <RequestArgumentType>\n */\npublic interface HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> {\n\n    Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shardRequests(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    Observable<BatchReturnType> createObservableCommand(Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    Observable<Void> mapResponseToRequests(Observable<BatchReturnType> batchResponse, Collection<CollapsedRequest<ResponseType, RequestArgumentType>> requests);\n\n    HystrixCollapserKey getCollapserKey();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/README.txt",
    "content": "====\n    Copyright 2016 Netflix, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n====\n\nThis package is not part of the public API and can change at any time. Do not rely upon any classes in this package.\n\nThe public API is com.netflix.hystrix.HystrixCollapser"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/RealCollapserTimer.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.lang.ref.Reference;\n\nimport com.netflix.hystrix.util.HystrixTimer;\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\n\n/**\n * Actual CollapserTimer implementation for triggering batch execution that uses HystrixTimer.\n */\npublic class RealCollapserTimer implements CollapserTimer {\n    /* single global timer that all collapsers will schedule their tasks on */\n    private final static HystrixTimer timer = HystrixTimer.getInstance();\n\n    @Override\n    public Reference<TimerListener> addListener(TimerListener collapseTask) {\n        return timer.addTimerListener(collapseTask);\n    }\n\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/RequestBatch.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.util.Collection;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.HystrixCollapserProperties;\n\n/**\n * A batch of requests collapsed together by a RequestCollapser instance. When full or time has expired it will execute and stop accepting further submissions.\n * \n * @param <BatchReturnType>\n * @param <ResponseType>\n * @param <RequestArgumentType>\n */\npublic class RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> {\n\n    private static final Logger logger = LoggerFactory.getLogger(RequestBatch.class);\n\n    private final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser;\n    private final int maxBatchSize;\n    private final AtomicBoolean batchStarted = new AtomicBoolean();\n\n    private final ConcurrentMap<RequestArgumentType, CollapsedRequest<ResponseType, RequestArgumentType>> argumentMap =\n            new ConcurrentHashMap<RequestArgumentType, CollapsedRequest<ResponseType, RequestArgumentType>>();\n    private final HystrixCollapserProperties properties;\n\n    private ReentrantReadWriteLock batchLock = new ReentrantReadWriteLock();\n\n    public RequestBatch(HystrixCollapserProperties properties, HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser, int maxBatchSize) {\n        this.properties = properties;\n        this.commandCollapser = commandCollapser;\n        this.maxBatchSize = maxBatchSize;\n    }\n\n    /**\n     * @return Observable if offer accepted, null if batch is full, already started or completed\n     */\n    public Observable<ResponseType> offer(RequestArgumentType arg) {\n        /* short-cut - if the batch is started we reject the offer */\n        if (batchStarted.get()) {\n            return null;\n        }\n\n        /*\n         * The 'read' just means non-exclusive even though we are writing.\n         */\n        if (batchLock.readLock().tryLock()) {\n            try {\n                /* double-check now that we have the lock - if the batch is started we reject the offer */\n                if (batchStarted.get()) {\n                    return null;\n                }\n\n                if (argumentMap.size() >= maxBatchSize) {\n                    return null;\n                } else {\n                    CollapsedRequestSubject<ResponseType, RequestArgumentType> collapsedRequest =\n                            new CollapsedRequestSubject<ResponseType, RequestArgumentType>(arg, this);\n                    final CollapsedRequestSubject<ResponseType, RequestArgumentType> existing = (CollapsedRequestSubject<ResponseType, RequestArgumentType>) argumentMap.putIfAbsent(arg, collapsedRequest);\n                    /**\n                     * If the argument already exists in the batch, then there are 2 options:\n                     * A) If request caching is ON (the default): only keep 1 argument in the batch and let all responses\n                     * be hooked up to that argument\n                     * B) If request caching is OFF: return an error to all duplicate argument requests\n                     *\n                     * This maintains the invariant that each batch has no duplicate arguments.  This prevents the impossible\n                     * logic (in a user-provided mapResponseToRequests for HystrixCollapser and the internals of HystrixObservableCollapser)\n                     * of trying to figure out which argument of a set of duplicates should get attached to a response.\n                     *\n                     * See https://github.com/Netflix/Hystrix/pull/1176 for further discussion.\n                     */\n                    if (existing != null) {\n                        boolean requestCachingEnabled = properties.requestCacheEnabled().get();\n                        if (requestCachingEnabled) {\n                            return existing.toObservable();\n                        } else {\n                            return Observable.error(new IllegalArgumentException(\"Duplicate argument in collapser batch : [\" + arg + \"]  This is not supported.  Please turn request-caching on for HystrixCollapser:\" + commandCollapser.getCollapserKey().name() + \" or prevent duplicates from making it into the batch!\"));\n                        }\n                    } else {\n                        return collapsedRequest.toObservable();\n                    }\n\n                }\n            } finally {\n                batchLock.readLock().unlock();\n            }\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Best-effort attempt to remove an argument from a batch.  This may get invoked when a cancellation occurs somewhere downstream.\n     * This method finds the argument in the batch, and removes it.\n     *\n     * @param arg argument to remove from batch\n     */\n    /* package-private */ void remove(RequestArgumentType arg) {\n        if (batchStarted.get()) {\n            //nothing we can do\n            return;\n        }\n\n        if (batchLock.readLock().tryLock()) {\n            try {\n                /* double-check now that we have the lock - if the batch is started, deleting is useless */\n                if (batchStarted.get()) {\n                    return;\n                }\n\n                argumentMap.remove(arg);\n            } finally {\n                batchLock.readLock().unlock();\n            }\n        }\n    }\n\n    /**\n     * Collapsed requests are triggered for batch execution and the array of arguments is passed in.\n     * <p>\n     * IMPORTANT IMPLEMENTATION DETAILS => The expected contract (responsibilities) of this method implementation is:\n     * <p>\n     * <ul>\n     * <li>Do NOT block => Do the work on a separate worker thread. Do not perform inline otherwise it will block other requests.</li>\n     * <li>Set ALL CollapsedRequest response values => Set the response values T on each CollapsedRequest<T, R>, even if the response is NULL otherwise the user thread waiting on the response will\n     * think a response was never received and will either block indefinitely or will timeout while waiting.</li>\n     * </ul>\n     * \n     */\n    public void executeBatchIfNotAlreadyStarted() {\n        /*\n         * - check that we only execute once since there's multiple paths to do so (timer, waiting thread or max batch size hit)\n         * - close the gate so 'offer' can no longer be invoked and we turn those threads away so they create a new batch\n         */\n        if (batchStarted.compareAndSet(false, true)) {\n            /* wait for 'offer'/'remove' threads to finish before executing the batch so 'requests' is complete */\n            batchLock.writeLock().lock();\n\n            try {\n                // shard batches\n                Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shards = commandCollapser.shardRequests(argumentMap.values());\n                // for each shard execute its requests \n                for (final Collection<CollapsedRequest<ResponseType, RequestArgumentType>> shardRequests : shards) {\n                    try {\n                        // create a new command to handle this batch of requests\n                        Observable<BatchReturnType> o = commandCollapser.createObservableCommand(shardRequests);\n\n                        commandCollapser.mapResponseToRequests(o, shardRequests).doOnError(new Action1<Throwable>() {\n\n                            /**\n                             * This handles failed completions\n                             */\n                            @Override\n                            public void call(Throwable e) {\n                                // handle Throwable in case anything is thrown so we don't block Observers waiting for onError/onCompleted\n                                Exception ee;\n                                if (e instanceof Exception) {\n                                    ee = (Exception) e;\n                                } else {\n                                    ee = new RuntimeException(\"Throwable caught while executing batch and mapping responses.\", e);\n                                }\n                                logger.debug(\"Exception mapping responses to requests.\", e);\n                                // if a failure occurs we want to pass that exception to all of the Futures that we've returned\n                                for (CollapsedRequest<ResponseType, RequestArgumentType> request : argumentMap.values()) {\n                                    try {\n                                        ((CollapsedRequestSubject<ResponseType, RequestArgumentType>) request).setExceptionIfResponseNotReceived(ee);\n                                    } catch (IllegalStateException e2) {\n                                        // if we have partial responses set in mapResponseToRequests\n                                        // then we may get IllegalStateException as we loop over them\n                                        // so we'll log but continue to the rest\n                                        logger.error(\"Partial success of 'mapResponseToRequests' resulted in IllegalStateException while setting Exception. Continuing ... \", e2);\n                                    }\n                                }\n                            }\n\n                        }).doOnCompleted(new Action0() {\n\n                            /**\n                             * This handles successful completions\n                             */\n                            @Override\n                            public void call() {\n                                // check that all requests had setResponse or setException invoked in case 'mapResponseToRequests' was implemented poorly\n                                Exception e = null;\n                                for (CollapsedRequest<ResponseType, RequestArgumentType> request : shardRequests) {\n                                    try {\n                                       e = ((CollapsedRequestSubject<ResponseType, RequestArgumentType>) request).setExceptionIfResponseNotReceived(e,\"No response set by \" + commandCollapser.getCollapserKey().name() + \" 'mapResponseToRequests' implementation.\");\n                                    } catch (IllegalStateException e2) {\n                                        logger.debug(\"Partial success of 'mapResponseToRequests' resulted in IllegalStateException while setting 'No response set' Exception. Continuing ... \", e2);\n                                    }\n                                }\n                            }\n\n                        }).subscribe();\n                        \n                    } catch (Exception e) {\n                        logger.error(\"Exception while creating and queueing command with batch.\", e);\n                        // if a failure occurs we want to pass that exception to all of the Futures that we've returned\n                        for (CollapsedRequest<ResponseType, RequestArgumentType> request : shardRequests) {\n                            try {\n                                request.setException(e);\n                            } catch (IllegalStateException e2) {\n                                logger.debug(\"Failed trying to setException on CollapsedRequest\", e2);\n                            }\n                        }\n                    }\n                }\n\n            } catch (Exception e) {\n                logger.error(\"Exception while sharding requests.\", e);\n                // same error handling as we do around the shards, but this is a wider net in case the shardRequest method fails\n                for (CollapsedRequest<ResponseType, RequestArgumentType> request : argumentMap.values()) {\n                    try {\n                        request.setException(e);\n                    } catch (IllegalStateException e2) {\n                        logger.debug(\"Failed trying to setException on CollapsedRequest\", e2);\n                    }\n                }\n            } finally {\n                batchLock.writeLock().unlock();\n            }\n        }\n    }\n\n    public void shutdown() {\n        // take the 'batchStarted' state so offers and execution will not be triggered elsewhere\n        if (batchStarted.compareAndSet(false, true)) {\n            // get the write lock so offers are synced with this (we don't really need to unlock as this is a one-shot deal to shutdown)\n            batchLock.writeLock().lock();\n            try {\n                // if we win the 'start' and once we have the lock we can now shut it down otherwise another thread will finish executing this batch\n                if (argumentMap.size() > 0) {\n                    logger.warn(\"Requests still exist in queue but will not be executed due to RequestCollapser shutdown: \" + argumentMap.size(), new IllegalStateException());\n                    /*\n                     * In the event that there is a concurrency bug or thread scheduling prevents the timer from ticking we need to handle this so the Future.get() calls do not block.\n                     * \n                     * I haven't been able to reproduce this use case on-demand but when stressing a machine saw this occur briefly right after the JVM paused (logs stopped scrolling).\n                     * \n                     * This safety-net just prevents the CollapsedRequestFutureImpl.get() from waiting on the CountDownLatch until its max timeout.\n                     */\n                    for (CollapsedRequest<ResponseType, RequestArgumentType> request : argumentMap.values()) {\n                        try {\n                            ((CollapsedRequestSubject<ResponseType, RequestArgumentType>) request).setExceptionIfResponseNotReceived(new IllegalStateException(\"Requests not executed before shutdown.\"));\n                        } catch (Exception e) {\n                            logger.debug(\"Failed to setException on CollapsedRequestFutureImpl instances.\", e);\n                        }\n                        /**\n                         * https://github.com/Netflix/Hystrix/issues/78 Include more info when collapsed requests remain in queue\n                         */\n                        logger.warn(\"Request still in queue but not be executed due to RequestCollapser shutdown. Argument => \" + request.getArgument() + \"   Request Object => \" + request, new IllegalStateException());\n                    }\n\n                }\n            } finally {\n                batchLock.writeLock().unlock();\n            }\n        }\n    }\n\n    public int getSize() {\n        return argumentMap.size();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/RequestCollapser.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.lang.ref.Reference;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport rx.Observable;\n\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextCallable;\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\n\n/**\n * Requests are submitted to this and batches executed based on size or time. Scoped to either a request or the global application.\n * <p>\n * Instances of this are retrieved from the RequestCollapserFactory.\n * \n * Must be thread-safe since it exists within a RequestVariable which is request-scoped and can be accessed from multiple threads.\n * \n * @ThreadSafe\n */\npublic class RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> {\n    static final Logger logger = LoggerFactory.getLogger(RequestCollapser.class);\n    static final Object NULL_SENTINEL = new Object();\n\n    private final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser;\n    // batch can be null once shutdown\n    private final AtomicReference<RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>> batch = new AtomicReference<RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>>();\n    private final AtomicReference<Reference<TimerListener>> timerListenerReference = new AtomicReference<Reference<TimerListener>>();\n    private final AtomicBoolean timerListenerRegistered = new AtomicBoolean();\n    private final CollapserTimer timer;\n    private final HystrixCollapserProperties properties;\n    private final HystrixConcurrencyStrategy concurrencyStrategy;\n\n    /**\n     * @param commandCollapser collapser which will create the batched requests and demultiplex the results\n     * @param properties collapser properties that define how collapsing occurs\n     * @param timer {@link CollapserTimer} which performs the collapsing\n     * @param concurrencyStrategy strategy for managing the {@link Callable}s generated by {@link RequestCollapser}\n     */\n    RequestCollapser(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser, HystrixCollapserProperties properties, CollapserTimer timer, HystrixConcurrencyStrategy concurrencyStrategy) {\n        this.commandCollapser = commandCollapser; // the command with implementation of abstract methods we need \n        this.concurrencyStrategy = concurrencyStrategy;\n        this.properties = properties;\n        this.timer = timer;\n        batch.set(new RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>(properties, commandCollapser, properties.maxRequestsInBatch().get()));\n    }\n\n    /**\n     * Submit a request to a batch. If the batch maxSize is hit trigger the batch immediately.\n     * \n     * @param arg argument to a {@link RequestCollapser}\n     * @return Observable<ResponseType>\n     * @throws IllegalStateException\n     *             if submitting after shutdown\n     */\n    public Observable<ResponseType> submitRequest(final RequestArgumentType arg) {\n        /*\n         * We only want the timer ticking if there are actually things to do so we register it the first time something is added.\n         */\n        if (!timerListenerRegistered.get() && timerListenerRegistered.compareAndSet(false, true)) {\n            /* schedule the collapsing task to be executed every x milliseconds (x defined inside CollapsedTask) */\n            timerListenerReference.set(timer.addListener(new CollapsedTask()));\n        }\n\n        // loop until succeed (compare-and-set spin-loop)\n        while (true) {\n            final RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> b = batch.get();\n            if (b == null) {\n                return Observable.error(new IllegalStateException(\"Submitting requests after collapser is shutdown\"));\n            }\n\n            final Observable<ResponseType> response;\n            if (arg != null) {\n                response = b.offer(arg);\n            } else {\n                response = b.offer( (RequestArgumentType) NULL_SENTINEL);\n            }\n            // it will always get an Observable unless we hit the max batch size\n            if (response != null) {\n                return response;\n            } else {\n                // this batch can't accept requests so create a new one and set it if another thread doesn't beat us\n                createNewBatchAndExecutePreviousIfNeeded(b);\n            }\n        }\n    }\n\n    private void createNewBatchAndExecutePreviousIfNeeded(RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> previousBatch) {\n        if (previousBatch == null) {\n            throw new IllegalStateException(\"Trying to start null batch which means it was shutdown already.\");\n        }\n        if (batch.compareAndSet(previousBatch, new RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>(properties, commandCollapser, properties.maxRequestsInBatch().get()))) {\n            // this thread won so trigger the previous batch\n            previousBatch.executeBatchIfNotAlreadyStarted();\n        }\n    }\n\n    /**\n     * Called from RequestVariable.shutdown() to unschedule the task.\n     */\n    public void shutdown() {\n        RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> currentBatch = batch.getAndSet(null);\n        if (currentBatch != null) {\n            currentBatch.shutdown();\n        }\n\n        if (timerListenerReference.get() != null) {\n            // if the timer was started we'll clear it so it stops ticking\n            timerListenerReference.get().clear();\n        }\n    }\n\n    /**\n     * Executed on each Timer interval execute the current batch if it has requests in it.\n     */\n    private class CollapsedTask implements TimerListener {\n        final Callable<Void> callableWithContextOfParent;\n\n        CollapsedTask() {\n            // this gets executed from the context of a HystrixCommand parent thread (such as a Tomcat thread)\n            // so we create the callable now where we can capture the thread context\n            callableWithContextOfParent = new HystrixContextCallable<Void>(concurrencyStrategy, new Callable<Void>() {\n                // the wrapCallable call allows a strategy to capture thread-context if desired\n\n                @Override\n                public Void call() throws Exception {\n                    try {\n                        // we fetch current so that when multiple threads race\n                        // we can do compareAndSet with the expected/new to ensure only one happens\n                        RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> currentBatch = batch.get();\n                        // 1) it can be null if it got shutdown\n                        // 2) we don't execute this batch if it has no requests and let it wait until next tick to be executed\n                        if (currentBatch != null && currentBatch.getSize() > 0) {\n                            // do execution within context of wrapped Callable\n                            createNewBatchAndExecutePreviousIfNeeded(currentBatch);\n                        }\n                    } catch (Throwable t) {\n                        logger.error(\"Error occurred trying to execute the batch.\", t);\n                        t.printStackTrace();\n                        // ignore error so we don't kill the Timer mainLoop and prevent further items from being scheduled\n                    }\n                    return null;\n                }\n\n            });\n        }\n\n        @Override\n        public void tick() {\n            try {\n                callableWithContextOfParent.call();\n            } catch (Exception e) {\n                logger.error(\"Error occurred trying to execute callable inside CollapsedTask from Timer.\", e);\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public int getIntervalTimeInMilliseconds() {\n            return properties.timerDelayInMilliseconds().get();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/collapser/RequestCollapserFactory.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableHolder;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport com.netflix.hystrix.util.HystrixTimer;\n\n/**\n * Factory for retrieving the correct instance of a RequestCollapser.\n * \n * @param <BatchReturnType>\n * @param <ResponseType>\n * @param <RequestArgumentType>\n */\npublic class RequestCollapserFactory<BatchReturnType, ResponseType, RequestArgumentType> {\n\n    private static final Logger logger = LoggerFactory.getLogger(RequestCollapserFactory.class);\n\n    private final CollapserTimer timer;\n    private final HystrixCollapserKey collapserKey;\n    private final HystrixCollapserProperties properties;\n    private final HystrixConcurrencyStrategy concurrencyStrategy;\n    private final Scope scope;\n\n    public static interface Scope {\n        String name();\n    }\n    \n    // internally expected scopes, dealing with the not-so-fun inheritance issues of enum when shared between classes\n    private static enum Scopes implements Scope {\n        REQUEST, GLOBAL\n    }\n    \n    public RequestCollapserFactory(HystrixCollapserKey collapserKey, Scope scope, CollapserTimer timer, HystrixCollapserProperties.Setter propertiesBuilder) {\n        this(collapserKey, scope, timer, HystrixPropertiesFactory.getCollapserProperties(collapserKey, propertiesBuilder));\n    }\n\n    public RequestCollapserFactory(HystrixCollapserKey collapserKey, Scope scope, CollapserTimer timer, HystrixCollapserProperties properties) {\n         /* strategy: ConcurrencyStrategy */\n        this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();\n        this.timer = timer;\n        this.scope = scope;\n        this.collapserKey = collapserKey;\n        this.properties = properties;\n\n    }\n\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserKey;\n    }\n\n    public Scope getScope() {\n        return scope;\n    }\n\n    public HystrixCollapserProperties getProperties() {\n        return properties;\n    }\n\n    public RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getRequestCollapser(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) {\n        if (Scopes.REQUEST == Scopes.valueOf(getScope().name())) {\n            return getCollapserForUserRequest(commandCollapser);\n        } else if (Scopes.GLOBAL == Scopes.valueOf(getScope().name())) {\n            return getCollapserForGlobalScope(commandCollapser);\n        } else {\n            logger.warn(\"Invalid Scope: {}  Defaulting to REQUEST scope.\", getScope());\n            return getCollapserForUserRequest(commandCollapser);\n        }\n    }\n\n    /**\n     * Static global cache of RequestCollapsers for Scope.GLOBAL\n     */\n    // String is CollapserKey.name() (we can't use CollapserKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static ConcurrentHashMap<String, RequestCollapser<?, ?, ?>> globalScopedCollapsers = new ConcurrentHashMap<String, RequestCollapser<?, ?, ?>>();\n\n    @SuppressWarnings(\"unchecked\")\n    private RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getCollapserForGlobalScope(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) {\n        RequestCollapser<?, ?, ?> collapser = globalScopedCollapsers.get(collapserKey.name());\n        if (collapser != null) {\n            return (RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>) collapser;\n        }\n        // create new collapser using 'this' first instance as the one that will get cached for future executions ('this' is stateless so we can do that)\n        RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> newCollapser = new RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>(commandCollapser, properties, timer, concurrencyStrategy);\n        RequestCollapser<?, ?, ?> existing = globalScopedCollapsers.putIfAbsent(collapserKey.name(), newCollapser);\n        if (existing == null) {\n            // we won\n            return newCollapser;\n        } else {\n            // we lost ... another thread beat us\n            // shutdown the one we created but didn't get stored\n            newCollapser.shutdown();\n            // return the existing one\n            return (RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>) existing;\n        }\n    }\n\n    /**\n     * Static global cache of RequestVariables with RequestCollapsers for Scope.REQUEST\n     */\n    // String is HystrixCollapserKey.name() (we can't use HystrixCollapserKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static ConcurrentHashMap<String, HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>>> requestScopedCollapsers = new ConcurrentHashMap<String, HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>>>();\n\n    /* we are casting because the Map needs to be <?, ?> but we know it is <ReturnType, RequestArgumentType> for this thread */\n    @SuppressWarnings(\"unchecked\")\n    private RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getCollapserForUserRequest(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) {\n        return (RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>) getRequestVariableForCommand(commandCollapser).get(concurrencyStrategy);\n    }\n\n    /**\n     * Lookup (or create and store) the RequestVariable for a given HystrixCollapserKey.\n     * \n     * @param commandCollapser collapser to retrieve {@link HystrixRequestVariableHolder} for\n     * @return HystrixRequestVariableHolder\n     */\n    @SuppressWarnings(\"unchecked\")\n    private HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> getRequestVariableForCommand(final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) {\n        HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> requestVariable = requestScopedCollapsers.get(commandCollapser.getCollapserKey().name());\n        if (requestVariable == null) {\n            // create new collapser using 'this' first instance as the one that will get cached for future executions ('this' is stateless so we can do that)\n            @SuppressWarnings({ \"rawtypes\" })\n            HystrixRequestVariableHolder newCollapser = new RequestCollapserRequestVariable(commandCollapser, properties, timer, concurrencyStrategy);\n            HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> existing = requestScopedCollapsers.putIfAbsent(commandCollapser.getCollapserKey().name(), newCollapser);\n            if (existing == null) {\n                // this thread won, so return the one we just created\n                requestVariable = newCollapser;\n            } else {\n                // another thread beat us (this should only happen when we have concurrency on the FIRST request for the life of the app for this HystrixCollapser class)\n                requestVariable = existing;\n                /*\n                 * This *should* be okay to discard the created object without cleanup as the RequestVariable implementation\n                 * should properly do lazy-initialization and only call initialValue() the first time get() is called.\n                 * \n                 * If it does not correctly follow this contract then there is a chance of a memory leak here.\n                 */\n            }\n        }\n        return requestVariable;\n    }\n\n    /**\n     * Clears all state. If new requests come in instances will be recreated and metrics started from scratch.\n     */\n    public static void reset() {\n        globalScopedCollapsers.clear();\n        requestScopedCollapsers.clear();\n        HystrixTimer.reset();\n    }\n\n    /**\n     * Used for testing\n     */\n    public static void resetRequest() {\n        requestScopedCollapsers.clear();\n    }\n\n    /**\n     * Used for testing\n     */\n    public static HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> getRequestVariable(String key) {\n        return requestScopedCollapsers.get(key);\n    }\n\n    /**\n     * Request scoped RequestCollapser that lives inside a RequestVariable.\n     * <p>\n     * This depends on the RequestVariable getting reset before each user request in NFFilter to ensure the RequestCollapser is new for each user request.\n     */\n    private final class RequestCollapserRequestVariable extends HystrixRequestVariableHolder<RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>> {\n\n        /**\n         * NOTE: There is only 1 instance of this for the life of the app per HystrixCollapser instance. The state changes on each request via the initialValue()/get() methods.\n         * <p>\n         * Thus, do NOT put any instance variables in this class that are not static for all threads.\n         */\n\n        private RequestCollapserRequestVariable(final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser, final HystrixCollapserProperties properties, final CollapserTimer timer, final HystrixConcurrencyStrategy concurrencyStrategy) {\n            super(new HystrixRequestVariableLifecycle<RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>>() {\n                @Override\n                public RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> initialValue() {\n                    // this gets calls once per request per HystrixCollapser instance\n                    return new RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>(commandCollapser, properties, timer, concurrencyStrategy);\n                }\n\n                @Override\n                public void shutdown(RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> currentCollapser) {\n                    // shut down the RequestCollapser (the internal timer tasks)\n                    if (currentCollapser != null) {\n                        currentCollapser.shutdown();\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixCollapserConfiguration.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\n\npublic class HystrixCollapserConfiguration {\n    private final HystrixCollapserKey collapserKey;\n    private final int maxRequestsInBatch;\n    private final int timerDelayInMilliseconds;\n    private final boolean requestCacheEnabled;\n    private final CollapserMetricsConfig collapserMetricsConfig;\n\n    public HystrixCollapserConfiguration(HystrixCollapserKey collapserKey, int maxRequestsInBatch, int timerDelayInMilliseconds,\n                                         boolean requestCacheEnabled, CollapserMetricsConfig collapserMetricsConfig) {\n        this.collapserKey = collapserKey;\n        this.maxRequestsInBatch = maxRequestsInBatch;\n        this.timerDelayInMilliseconds = timerDelayInMilliseconds;\n        this.requestCacheEnabled = requestCacheEnabled;\n        this.collapserMetricsConfig = collapserMetricsConfig;\n    }\n\n    public static HystrixCollapserConfiguration sample(HystrixCollapserKey collapserKey, HystrixCollapserProperties collapserProperties) {\n        CollapserMetricsConfig collapserMetricsConfig = new CollapserMetricsConfig(\n                collapserProperties.metricsRollingPercentileWindowBuckets().get(),\n                collapserProperties.metricsRollingPercentileWindowInMilliseconds().get(),\n                collapserProperties.metricsRollingPercentileEnabled().get(),\n                collapserProperties.metricsRollingStatisticalWindowBuckets().get(),\n                collapserProperties.metricsRollingStatisticalWindowInMilliseconds().get()\n        );\n\n        return new HystrixCollapserConfiguration(\n                collapserKey,\n                collapserProperties.maxRequestsInBatch().get(),\n                collapserProperties.timerDelayInMilliseconds().get(),\n                collapserProperties.requestCacheEnabled().get(),\n                collapserMetricsConfig\n        );\n    }\n\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserKey;\n    }\n\n    public int getMaxRequestsInBatch() {\n        return maxRequestsInBatch;\n    }\n\n    public int getTimerDelayInMilliseconds() {\n        return timerDelayInMilliseconds;\n    }\n\n    public boolean isRequestCacheEnabled() {\n        return requestCacheEnabled;\n    }\n\n    public CollapserMetricsConfig getCollapserMetricsConfig() {\n        return collapserMetricsConfig;\n    }\n\n    public static class CollapserMetricsConfig {\n        private final int rollingPercentileNumberOfBuckets;\n        private final int rollingPercentileBucketSizeInMilliseconds;\n        private final boolean rollingPercentileEnabled;\n        private final int rollingCounterNumberOfBuckets;\n        private final int rollingCounterBucketSizeInMilliseconds;\n\n        public CollapserMetricsConfig(int rollingPercentileNumberOfBuckets, int rollingPercentileBucketSizeInMilliseconds, boolean rollingPercentileEnabled,\n                                      int rollingCounterNumberOfBuckets, int rollingCounterBucketSizeInMilliseconds) {\n            this.rollingPercentileNumberOfBuckets = rollingCounterNumberOfBuckets;\n            this.rollingPercentileBucketSizeInMilliseconds = rollingPercentileBucketSizeInMilliseconds;\n            this.rollingPercentileEnabled = rollingPercentileEnabled;\n            this.rollingCounterNumberOfBuckets = rollingCounterNumberOfBuckets;\n            this.rollingCounterBucketSizeInMilliseconds = rollingCounterBucketSizeInMilliseconds;\n        }\n\n        public int getRollingPercentileNumberOfBuckets() {\n            return rollingPercentileNumberOfBuckets;\n        }\n\n        public int getRollingPercentileBucketSizeInMilliseconds() {\n            return rollingPercentileBucketSizeInMilliseconds;\n        }\n\n        public boolean isRollingPercentileEnabled() {\n            return rollingPercentileEnabled;\n        }\n\n        public int getRollingCounterNumberOfBuckets() {\n            return rollingCounterNumberOfBuckets;\n        }\n\n        public int getRollingCounterBucketSizeInMilliseconds() {\n            return rollingCounterBucketSizeInMilliseconds;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixCommandConfiguration.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\n\npublic class HystrixCommandConfiguration {\n    //The idea is for this object to be serialized off-box.  For future-proofing, I'm adding a version so that changing config over time can be handled gracefully\n    private static final String VERSION = \"1\";\n    private final HystrixCommandKey commandKey;\n    private final HystrixThreadPoolKey threadPoolKey;\n    private final HystrixCommandGroupKey groupKey;\n    private final HystrixCommandExecutionConfig executionConfig;\n    private final HystrixCommandCircuitBreakerConfig circuitBreakerConfig;\n    private final HystrixCommandMetricsConfig metricsConfig;\n\n    public HystrixCommandConfiguration(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey, HystrixCommandGroupKey groupKey,\n                                       HystrixCommandExecutionConfig executionConfig,\n                                       HystrixCommandCircuitBreakerConfig circuitBreakerConfig,\n                                       HystrixCommandMetricsConfig metricsConfig) {\n        this.commandKey = commandKey;\n        this.threadPoolKey = threadPoolKey;\n        this.groupKey = groupKey;\n        this.executionConfig = executionConfig;\n        this.circuitBreakerConfig = circuitBreakerConfig;\n        this.metricsConfig = metricsConfig;\n    }\n\n    public static HystrixCommandConfiguration sample(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey,\n                                                     HystrixCommandGroupKey groupKey, HystrixCommandProperties commandProperties) {\n        HystrixCommandExecutionConfig executionConfig = new HystrixCommandExecutionConfig(\n                commandProperties.executionIsolationSemaphoreMaxConcurrentRequests().get(),\n                commandProperties.executionIsolationStrategy().get(),\n                commandProperties.executionIsolationThreadInterruptOnTimeout().get(),\n                commandProperties.executionIsolationThreadPoolKeyOverride().get(),\n                commandProperties.executionTimeoutEnabled().get(),\n                commandProperties.executionTimeoutInMilliseconds().get(),\n                commandProperties.fallbackEnabled().get(),\n                commandProperties.fallbackIsolationSemaphoreMaxConcurrentRequests().get(),\n                commandProperties.requestCacheEnabled().get(),\n                commandProperties.requestLogEnabled().get()\n        );\n\n        HystrixCommandCircuitBreakerConfig circuitBreakerConfig = new HystrixCommandCircuitBreakerConfig(\n                commandProperties.circuitBreakerEnabled().get(),\n                commandProperties.circuitBreakerErrorThresholdPercentage().get(),\n                commandProperties.circuitBreakerForceClosed().get(),\n                commandProperties.circuitBreakerForceOpen().get(),\n                commandProperties.circuitBreakerRequestVolumeThreshold().get(),\n                commandProperties.circuitBreakerSleepWindowInMilliseconds().get()\n        );\n\n        HystrixCommandMetricsConfig metricsConfig = new HystrixCommandMetricsConfig(\n                commandProperties.metricsHealthSnapshotIntervalInMilliseconds().get(),\n                commandProperties.metricsRollingPercentileEnabled().get(),\n                commandProperties.metricsRollingPercentileWindowBuckets().get(),\n                commandProperties.metricsRollingPercentileWindowInMilliseconds().get(),\n                commandProperties.metricsRollingStatisticalWindowBuckets().get(),\n                commandProperties.metricsRollingStatisticalWindowInMilliseconds().get()\n        );\n\n        return new HystrixCommandConfiguration(\n                commandKey, threadPoolKey, groupKey, executionConfig, circuitBreakerConfig, metricsConfig);\n    }\n\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    public HystrixCommandGroupKey getGroupKey() {\n        return groupKey;\n    }\n\n    public HystrixCommandExecutionConfig getExecutionConfig() {\n        return executionConfig;\n    }\n\n    public HystrixCommandCircuitBreakerConfig getCircuitBreakerConfig() {\n        return circuitBreakerConfig;\n    }\n\n    public HystrixCommandMetricsConfig getMetricsConfig() {\n        return metricsConfig;\n    }\n\n    public static class HystrixCommandCircuitBreakerConfig {\n        private final boolean enabled;\n        private final int errorThresholdPercentage;\n        private final boolean forceClosed;\n        private final boolean forceOpen;\n        private final int requestVolumeThreshold;\n        private final int sleepWindowInMilliseconds;\n\n        public HystrixCommandCircuitBreakerConfig(boolean enabled, int errorThresholdPercentage, boolean forceClosed,\n                                                  boolean forceOpen, int requestVolumeThreshold, int sleepWindowInMilliseconds) {\n            this.enabled = enabled;\n            this.errorThresholdPercentage = errorThresholdPercentage;\n            this.forceClosed = forceClosed;\n            this.forceOpen = forceOpen;\n            this.requestVolumeThreshold = requestVolumeThreshold;\n            this.sleepWindowInMilliseconds = sleepWindowInMilliseconds;\n        }\n\n        public boolean isEnabled() {\n            return enabled;\n        }\n\n        public int getErrorThresholdPercentage() {\n            return errorThresholdPercentage;\n        }\n\n        public boolean isForceClosed() {\n            return forceClosed;\n        }\n\n        public boolean isForceOpen() {\n            return forceOpen;\n        }\n\n        public int getRequestVolumeThreshold() {\n            return requestVolumeThreshold;\n        }\n\n        public int getSleepWindowInMilliseconds() {\n            return sleepWindowInMilliseconds;\n        }\n    }\n\n    public static class HystrixCommandExecutionConfig {\n        private final int semaphoreMaxConcurrentRequests;\n        private final HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy;\n        private final boolean threadInterruptOnTimeout;\n        private final String threadPoolKeyOverride;\n        private final boolean timeoutEnabled;\n        private final int timeoutInMilliseconds;\n        private final boolean fallbackEnabled;\n        private final int fallbackMaxConcurrentRequest;\n        private final boolean requestCacheEnabled;\n        private final boolean requestLogEnabled;\n\n        public HystrixCommandExecutionConfig(int semaphoreMaxConcurrentRequests, HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy,\n                                             boolean threadInterruptOnTimeout, String threadPoolKeyOverride, boolean timeoutEnabled,\n                                             int timeoutInMilliseconds, boolean fallbackEnabled, int fallbackMaxConcurrentRequests,\n                                             boolean requestCacheEnabled, boolean requestLogEnabled) {\n            this.semaphoreMaxConcurrentRequests = semaphoreMaxConcurrentRequests;\n            this.isolationStrategy = isolationStrategy;\n            this.threadInterruptOnTimeout = threadInterruptOnTimeout;\n            this.threadPoolKeyOverride = threadPoolKeyOverride;\n            this.timeoutEnabled = timeoutEnabled;\n            this.timeoutInMilliseconds = timeoutInMilliseconds;\n            this.fallbackEnabled = fallbackEnabled;\n            this.fallbackMaxConcurrentRequest = fallbackMaxConcurrentRequests;\n            this.requestCacheEnabled = requestCacheEnabled;\n            this.requestLogEnabled = requestLogEnabled;\n\n        }\n\n        public int getSemaphoreMaxConcurrentRequests() {\n            return semaphoreMaxConcurrentRequests;\n        }\n\n        public HystrixCommandProperties.ExecutionIsolationStrategy getIsolationStrategy() {\n            return isolationStrategy;\n        }\n\n        public boolean isThreadInterruptOnTimeout() {\n            return threadInterruptOnTimeout;\n        }\n\n        public String getThreadPoolKeyOverride() {\n            return threadPoolKeyOverride;\n        }\n\n        public boolean isTimeoutEnabled() {\n            return timeoutEnabled;\n        }\n\n        public int getTimeoutInMilliseconds() {\n            return timeoutInMilliseconds;\n        }\n\n        public boolean isFallbackEnabled() {\n            return fallbackEnabled;\n        }\n\n        public int getFallbackMaxConcurrentRequest() {\n            return fallbackMaxConcurrentRequest;\n        }\n\n        public boolean isRequestCacheEnabled() {\n            return requestCacheEnabled;\n        }\n\n        public boolean isRequestLogEnabled() {\n            return requestLogEnabled;\n        }\n    }\n\n    public static class HystrixCommandMetricsConfig {\n        private final int healthIntervalInMilliseconds;\n        private final boolean rollingPercentileEnabled;\n        private final int rollingPercentileNumberOfBuckets;\n        private final int rollingPercentileBucketSizeInMilliseconds;\n        private final int rollingCounterNumberOfBuckets;\n        private final int rollingCounterBucketSizeInMilliseconds;\n\n        public HystrixCommandMetricsConfig(int healthIntervalInMilliseconds, boolean rollingPercentileEnabled, int rollingPercentileNumberOfBuckets,\n                                           int rollingPercentileBucketSizeInMilliseconds, int rollingCounterNumberOfBuckets,\n                                           int rollingCounterBucketSizeInMilliseconds) {\n            this.healthIntervalInMilliseconds = healthIntervalInMilliseconds;\n            this.rollingPercentileEnabled = rollingPercentileEnabled;\n            this.rollingPercentileNumberOfBuckets = rollingPercentileNumberOfBuckets;\n            this.rollingPercentileBucketSizeInMilliseconds = rollingPercentileBucketSizeInMilliseconds;\n            this.rollingCounterNumberOfBuckets = rollingCounterNumberOfBuckets;\n            this.rollingCounterBucketSizeInMilliseconds = rollingCounterBucketSizeInMilliseconds;\n        }\n\n        public int getHealthIntervalInMilliseconds() {\n            return healthIntervalInMilliseconds;\n        }\n\n        public boolean isRollingPercentileEnabled() {\n            return rollingPercentileEnabled;\n        }\n\n        public int getRollingPercentileNumberOfBuckets() {\n            return rollingPercentileNumberOfBuckets;\n        }\n\n        public int getRollingPercentileBucketSizeInMilliseconds() {\n            return rollingPercentileBucketSizeInMilliseconds;\n        }\n\n        public int getRollingCounterNumberOfBuckets() {\n            return rollingCounterNumberOfBuckets;\n        }\n\n        public int getRollingCounterBucketSizeInMilliseconds() {\n            return rollingCounterBucketSizeInMilliseconds;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixConfiguration.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\n\nimport java.util.Map;\n\npublic class HystrixConfiguration {\n    private final Map<HystrixCommandKey, HystrixCommandConfiguration> commandConfig;\n    private final Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> threadPoolConfig;\n    private final Map<HystrixCollapserKey, HystrixCollapserConfiguration> collapserConfig;\n\n    public HystrixConfiguration(Map<HystrixCommandKey, HystrixCommandConfiguration> commandConfig,\n                                 Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> threadPoolConfig,\n                                 Map<HystrixCollapserKey, HystrixCollapserConfiguration> collapserConfig) {\n        this.commandConfig = commandConfig;\n        this.threadPoolConfig = threadPoolConfig;\n        this.collapserConfig = collapserConfig;\n    }\n\n    public static HystrixConfiguration from(Map<HystrixCommandKey, HystrixCommandConfiguration> commandConfig,\n                                            Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> threadPoolConfig,\n                                            Map<HystrixCollapserKey, HystrixCollapserConfiguration> collapserConfig) {\n        return new HystrixConfiguration(commandConfig, threadPoolConfig, collapserConfig);\n    }\n\n    public Map<HystrixCommandKey, HystrixCommandConfiguration> getCommandConfig() {\n        return commandConfig;\n    }\n\n    public Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> getThreadPoolConfig() {\n        return threadPoolConfig;\n    }\n\n    public Map<HystrixCollapserKey, HystrixCollapserConfiguration> getCollapserConfig() {\n        return collapserConfig;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixConfigurationStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * This class samples current Hystrix configuration and exposes that as a stream\n */\npublic class HystrixConfigurationStream {\n\n    private final int intervalInMilliseconds;\n    private final Observable<HystrixConfiguration> allConfigurationStream;\n    private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);\n\n    private static final DynamicIntProperty dataEmissionIntervalInMs =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.stream.config.intervalInMilliseconds\", 5000);\n\n\n    private static final Func1<Long, HystrixConfiguration> getAllConfig =\n            new Func1<Long, HystrixConfiguration>() {\n                @Override\n                public HystrixConfiguration call(Long timestamp) {\n                    return HystrixConfiguration.from(\n                            getAllCommandConfig.call(timestamp),\n                            getAllThreadPoolConfig.call(timestamp),\n                            getAllCollapserConfig.call(timestamp)\n                    );\n                }\n            };\n\n    /**\n     * @deprecated Not for public use.  Please use {@link #getInstance()}.  This facilitates better stream-sharing\n     * @param intervalInMilliseconds milliseconds between data emissions\n     */\n    @Deprecated //deprecated in 1.5.4.\n    public HystrixConfigurationStream(final int intervalInMilliseconds) {\n        this.intervalInMilliseconds = intervalInMilliseconds;\n        this.allConfigurationStream = Observable.interval(intervalInMilliseconds, TimeUnit.MILLISECONDS)\n                .map(getAllConfig)\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(true);\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(false);\n                    }\n                })\n                .share()\n                .onBackpressureDrop();\n    }\n\n    //The data emission interval is looked up on startup only\n    private static final HystrixConfigurationStream INSTANCE =\n            new HystrixConfigurationStream(dataEmissionIntervalInMs.get());\n\n    public static HystrixConfigurationStream getInstance() {\n        return INSTANCE;\n    }\n\n    static HystrixConfigurationStream getNonSingletonInstanceOnlyUsedInUnitTests(int delayInMs) {\n        return new HystrixConfigurationStream(delayInMs);\n    }\n\n    /**\n     * Return a ref-counted stream that will only do work when at least one subscriber is present\n     */\n    public Observable<HystrixConfiguration> observe() {\n        return allConfigurationStream;\n    }\n\n    public Observable<Map<HystrixCommandKey, HystrixCommandConfiguration>> observeCommandConfiguration() {\n        return allConfigurationStream.map(getOnlyCommandConfig);\n    }\n\n    public Observable<Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>> observeThreadPoolConfiguration() {\n        return allConfigurationStream.map(getOnlyThreadPoolConfig);\n    }\n\n    public Observable<Map<HystrixCollapserKey, HystrixCollapserConfiguration>> observeCollapserConfiguration() {\n        return allConfigurationStream.map(getOnlyCollapserConfig);\n    }\n\n    public int getIntervalInMilliseconds() {\n        return this.intervalInMilliseconds;\n    }\n\n    public boolean isSourceCurrentlySubscribed() {\n        return isSourceCurrentlySubscribed.get();\n    }\n\n    private static HystrixCommandConfiguration sampleCommandConfiguration(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey,\n                                                                          HystrixCommandGroupKey groupKey, HystrixCommandProperties commandProperties) {\n        return HystrixCommandConfiguration.sample(commandKey, threadPoolKey, groupKey, commandProperties);\n    }\n\n    private static HystrixThreadPoolConfiguration sampleThreadPoolConfiguration(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {\n        return HystrixThreadPoolConfiguration.sample(threadPoolKey, threadPoolProperties);\n    }\n\n    private static HystrixCollapserConfiguration sampleCollapserConfiguration(HystrixCollapserKey collapserKey, HystrixCollapserProperties collapserProperties) {\n        return HystrixCollapserConfiguration.sample(collapserKey, collapserProperties);\n    }\n\n    private static final Func1<Long, Map<HystrixCommandKey, HystrixCommandConfiguration>> getAllCommandConfig =\n            new Func1<Long, Map<HystrixCommandKey, HystrixCommandConfiguration>>() {\n                @Override\n                public Map<HystrixCommandKey, HystrixCommandConfiguration> call(Long timestamp) {\n                    Map<HystrixCommandKey, HystrixCommandConfiguration> commandConfigPerKey = new HashMap<HystrixCommandKey, HystrixCommandConfiguration>();\n                    for (HystrixCommandMetrics commandMetrics: HystrixCommandMetrics.getInstances()) {\n                        HystrixCommandKey commandKey = commandMetrics.getCommandKey();\n                        HystrixThreadPoolKey threadPoolKey = commandMetrics.getThreadPoolKey();\n                        HystrixCommandGroupKey groupKey = commandMetrics.getCommandGroup();\n                        commandConfigPerKey.put(commandKey, sampleCommandConfiguration(commandKey, threadPoolKey, groupKey, commandMetrics.getProperties()));\n                    }\n                    return commandConfigPerKey;\n                }\n            };\n\n    private static final Func1<Long, Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>> getAllThreadPoolConfig =\n            new Func1<Long, Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>>() {\n                @Override\n                public Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> call(Long timestamp) {\n                    Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> threadPoolConfigPerKey = new HashMap<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>();\n                    for (HystrixThreadPoolMetrics threadPoolMetrics: HystrixThreadPoolMetrics.getInstances()) {\n                        HystrixThreadPoolKey threadPoolKey = threadPoolMetrics.getThreadPoolKey();\n                        threadPoolConfigPerKey.put(threadPoolKey, sampleThreadPoolConfiguration(threadPoolKey, threadPoolMetrics.getProperties()));\n                    }\n                    return threadPoolConfigPerKey;\n                }\n            };\n\n    private static final Func1<Long, Map<HystrixCollapserKey, HystrixCollapserConfiguration>> getAllCollapserConfig =\n            new Func1<Long, Map<HystrixCollapserKey, HystrixCollapserConfiguration>>() {\n                @Override\n                public Map<HystrixCollapserKey, HystrixCollapserConfiguration> call(Long timestamp) {\n                    Map<HystrixCollapserKey, HystrixCollapserConfiguration> collapserConfigPerKey = new HashMap<HystrixCollapserKey, HystrixCollapserConfiguration>();\n                    for (HystrixCollapserMetrics collapserMetrics: HystrixCollapserMetrics.getInstances()) {\n                        HystrixCollapserKey collapserKey = collapserMetrics.getCollapserKey();\n                        collapserConfigPerKey.put(collapserKey, sampleCollapserConfiguration(collapserKey, collapserMetrics.getProperties()));\n                    }\n                    return collapserConfigPerKey;\n                }\n            };\n\n\n\n    private static final Func1<HystrixConfiguration, Map<HystrixCommandKey, HystrixCommandConfiguration>> getOnlyCommandConfig =\n            new Func1<HystrixConfiguration, Map<HystrixCommandKey, HystrixCommandConfiguration>>() {\n                @Override\n                public Map<HystrixCommandKey, HystrixCommandConfiguration> call(HystrixConfiguration hystrixConfiguration) {\n                    return hystrixConfiguration.getCommandConfig();\n                }\n            };\n\n    private static final Func1<HystrixConfiguration, Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>> getOnlyThreadPoolConfig =\n            new Func1<HystrixConfiguration, Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>>() {\n                @Override\n                public Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> call(HystrixConfiguration hystrixConfiguration) {\n                    return hystrixConfiguration.getThreadPoolConfig();\n                }\n            };\n\n    private static final Func1<HystrixConfiguration, Map<HystrixCollapserKey, HystrixCollapserConfiguration>> getOnlyCollapserConfig =\n            new Func1<HystrixConfiguration, Map<HystrixCollapserKey, HystrixCollapserConfiguration>>() {\n                @Override\n                public Map<HystrixCollapserKey, HystrixCollapserConfiguration> call(HystrixConfiguration hystrixConfiguration) {\n                    return hystrixConfiguration.getCollapserConfig();\n                }\n            };\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/config/HystrixThreadPoolConfiguration.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\n\npublic class HystrixThreadPoolConfiguration {\n    private final HystrixThreadPoolKey threadPoolKey;\n    private final int coreSize;\n    private final int maximumSize;\n    private final int actualMaximumSize;\n    private final int maxQueueSize;\n    private final int queueRejectionThreshold;\n    private final int keepAliveTimeInMinutes;\n    private final boolean allowMaximumSizeToDivergeFromCoreSize;\n    private final int rollingCounterNumberOfBuckets;\n    private final int rollingCounterBucketSizeInMilliseconds;\n\n    private HystrixThreadPoolConfiguration(HystrixThreadPoolKey threadPoolKey, int coreSize, int maximumSize, int actualMaximumSize, int maxQueueSize, int queueRejectionThreshold,\n                                           int keepAliveTimeInMinutes, boolean allowMaximumSizeToDivergeFromCoreSize, int rollingCounterNumberOfBuckets,\n                                           int rollingCounterBucketSizeInMilliseconds) {\n        this.threadPoolKey = threadPoolKey;\n        this.allowMaximumSizeToDivergeFromCoreSize = allowMaximumSizeToDivergeFromCoreSize;\n        this.coreSize = coreSize;\n        this.maximumSize = maximumSize;\n        this.actualMaximumSize = actualMaximumSize;\n        this.maxQueueSize = maxQueueSize;\n        this.queueRejectionThreshold = queueRejectionThreshold;\n        this.keepAliveTimeInMinutes = keepAliveTimeInMinutes;\n        this.rollingCounterNumberOfBuckets = rollingCounterNumberOfBuckets;\n        this.rollingCounterBucketSizeInMilliseconds = rollingCounterBucketSizeInMilliseconds;\n    }\n\n    private HystrixThreadPoolConfiguration(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {\n        this(threadPoolKey, threadPoolProperties.coreSize().get(),\n                threadPoolProperties.maximumSize().get(), threadPoolProperties.actualMaximumSize(),\n                threadPoolProperties.maxQueueSize().get(), threadPoolProperties.queueSizeRejectionThreshold().get(),\n                threadPoolProperties.keepAliveTimeMinutes().get(), threadPoolProperties.getAllowMaximumSizeToDivergeFromCoreSize().get(),\n                threadPoolProperties.metricsRollingStatisticalWindowBuckets().get(),\n                threadPoolProperties.metricsRollingStatisticalWindowInMilliseconds().get());\n    }\n\n    public static HystrixThreadPoolConfiguration sample(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {\n        return new HystrixThreadPoolConfiguration(threadPoolKey, threadPoolProperties);\n    }\n\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    public int getCoreSize() {\n        return coreSize;\n    }\n\n    /**\n     * Simple getter that returns what the `maximumSize` property is configured as\n     * @return\n     */\n    public int getMaximumSize() {\n        return maximumSize;\n    }\n\n    /**\n     * Given all of the thread pool configuration, what is the actual maximumSize applied to the thread pool.\n     *\n     * Cases:\n     * 1) allowMaximumSizeToDivergeFromCoreSize == false: maximumSize is set to coreSize\n     * 2) allowMaximumSizeToDivergeFromCoreSize == true, maximumSize >= coreSize: thread pool has different core/max sizes, so return the configured max\n     * 3) allowMaximumSizeToDivergeFromCoreSize == true, maximumSize < coreSize: threadpool incorrectly configured, use coreSize for max size\n     * @return actually configured maximum size of threadpool\n     */\n    public int getActualMaximumSize() {\n        return this.actualMaximumSize;\n    }\n\n    public int getMaxQueueSize() {\n        return maxQueueSize;\n    }\n\n    public int getQueueRejectionThreshold() {\n        return queueRejectionThreshold;\n    }\n\n    public int getKeepAliveTimeInMinutes() {\n        return keepAliveTimeInMinutes;\n    }\n\n    public boolean getAllowMaximumSizeToDivergeFromCoreSize() {\n        return allowMaximumSizeToDivergeFromCoreSize;\n    }\n\n    public int getRollingCounterNumberOfBuckets() {\n        return rollingCounterNumberOfBuckets;\n    }\n\n    public int getRollingCounterBucketSizeInMilliseconds() {\n        return rollingCounterBucketSizeInMilliseconds;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/exception/ExceptionNotWrappedByHystrix.java",
    "content": "package com.netflix.hystrix.exception;\n\n/**\n * Exceptions can implement this interface to prevent Hystrix from wrapping detected exceptions in a HystrixRuntimeException\n */\npublic interface ExceptionNotWrappedByHystrix {\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/exception/HystrixBadRequestException.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.exception;\n\nimport com.netflix.hystrix.HystrixCommand;\n\n/**\n * An exception representing an error with provided arguments or state rather than an execution failure.\n * <p>\n * Unlike all other exceptions thrown by a {@link HystrixCommand} this will not trigger fallback, not count against failure metrics and thus not trigger the circuit breaker.\n * <p>\n * NOTE: This should <b>only</b> be used when an error is due to user input such as {@link IllegalArgumentException} otherwise it defeats the purpose of fault-tolerance and fallback behavior.\n */\npublic class HystrixBadRequestException extends RuntimeException {\n\n    private static final long serialVersionUID = -8341452103561805856L;\n\n    public HystrixBadRequestException(String message) {\n        super(message);\n    }\n\n    public HystrixBadRequestException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/exception/HystrixRuntimeException.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.exception;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.util.ExceptionThreadingUtility;\n\n/**\n * RuntimeException that is thrown when a {@link HystrixCommand} fails and does not have a fallback.\n */\n@SuppressWarnings(\"rawtypes\")\npublic class HystrixRuntimeException extends RuntimeException {\n\n    private static final long serialVersionUID = 5219160375476046229L;\n\n    private final Class<? extends HystrixInvokable> commandClass;\n    private final Throwable fallbackException;\n    private final FailureType failureCause;\n\n    public static enum FailureType {\n        BAD_REQUEST_EXCEPTION, COMMAND_EXCEPTION, TIMEOUT, SHORTCIRCUIT, REJECTED_THREAD_EXECUTION, REJECTED_SEMAPHORE_EXECUTION, REJECTED_SEMAPHORE_FALLBACK\n    }\n\n    public HystrixRuntimeException(FailureType failureCause, Class<? extends HystrixInvokable> commandClass, String message, Exception cause, Throwable fallbackException) {\n        super(message, cause);\n        this.failureCause = failureCause;\n        this.commandClass = commandClass;\n        this.fallbackException = fallbackException;\n    }\n\n    public HystrixRuntimeException(FailureType failureCause, Class<? extends HystrixInvokable> commandClass, String message, Throwable cause, Throwable fallbackException) {\n        super(message, cause);\n        this.failureCause = failureCause;\n        this.commandClass = commandClass;\n        this.fallbackException = fallbackException;\n    }\n\n    /**\n     * The type of failure that caused this exception to be thrown.\n     * \n     * @return {@link FailureType}\n     */\n    public FailureType getFailureType() {\n        return failureCause;\n    }\n\n    /**\n     * The implementing class of the {@link HystrixCommand}.\n     * \n     * @return {@code Class<? extends HystrixCommand> }\n     */\n    public Class<? extends HystrixInvokable> getImplementingClass() {\n        return commandClass;\n    }\n\n    /**\n     * The {@link Throwable} that was thrown when trying to retrieve a fallback.\n     * \n     * @return {@link Throwable}\n     */\n    public Throwable getFallbackException() {\n        return fallbackException;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/exception/HystrixTimeoutException.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.exception;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixObservableCommand;\n\n/**\n * An exception representing an error where the provided execution method took longer than the Hystrix timeout.\n * <p>\n * Hystrix will trigger an exception of this type if it times out an execution.  This class is public, so\n * user-defined execution methods ({@link HystrixCommand#run()} / {@link HystrixObservableCommand#construct()) may also\n * throw this error.  If you want some types of failures to be counted as timeouts, you may wrap those failures in\n * a HystrixTimeoutException.  See https://github.com/Netflix/Hystrix/issues/920 for more discussion.\n */\npublic class HystrixTimeoutException extends Exception {\n\n    private static final long serialVersionUID = -5085623652043595962L;\n\n}\n\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/exception/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Custom exception implementations.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.exception;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/CachedValuesHistogram.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport org.HdrHistogram.Histogram;\n\npublic class CachedValuesHistogram {\n\n    private final static int NUMBER_SIGNIFICANT_DIGITS = 3;\n\n    private final int mean;\n    private final int p0;\n    private final int p5;\n    private final int p10;\n    private final int p15;\n    private final int p20;\n    private final int p25;\n    private final int p30;\n    private final int p35;\n    private final int p40;\n    private final int p45;\n    private final int p50;\n    private final int p55;\n    private final int p60;\n    private final int p65;\n    private final int p70;\n    private final int p75;\n    private final int p80;\n    private final int p85;\n    private final int p90;\n    private final int p95;\n    private final int p99;\n    private final int p99_5;\n    private final int p99_9;\n    private final int p99_95;\n    private final int p99_99;\n    private final int p100;\n\n    private final long totalCount;\n\n    public static CachedValuesHistogram backedBy(Histogram underlying) {\n        return new CachedValuesHistogram(underlying);\n    }\n\n    private CachedValuesHistogram(Histogram underlying) {\n        /**\n         * Single thread calculates a variety of commonly-accessed quantities.\n         * This way, all threads can access the cached values without synchronization\n         * Synchronization is only required for values that are not cached\n         */\n\n        mean = (int) underlying.getMean();\n        p0 = (int) underlying.getValueAtPercentile(0);\n        p5 = (int) underlying.getValueAtPercentile(5);\n        p10 = (int) underlying.getValueAtPercentile(10);\n        p15 = (int) underlying.getValueAtPercentile(15);\n        p20 = (int) underlying.getValueAtPercentile(20);\n        p25 = (int) underlying.getValueAtPercentile(25);\n        p30 = (int) underlying.getValueAtPercentile(30);\n        p35 = (int) underlying.getValueAtPercentile(35);\n        p40 = (int) underlying.getValueAtPercentile(40);\n        p45 = (int) underlying.getValueAtPercentile(45);\n        p50 = (int) underlying.getValueAtPercentile(50);\n        p55 = (int) underlying.getValueAtPercentile(55);\n        p60 = (int) underlying.getValueAtPercentile(60);\n        p65 = (int) underlying.getValueAtPercentile(65);\n        p70 = (int) underlying.getValueAtPercentile(70);\n        p75 = (int) underlying.getValueAtPercentile(75);\n        p80 = (int) underlying.getValueAtPercentile(80);\n        p85 = (int) underlying.getValueAtPercentile(85);\n        p90 = (int) underlying.getValueAtPercentile(90);\n        p95 = (int) underlying.getValueAtPercentile(95);\n        p99 = (int) underlying.getValueAtPercentile(99);\n        p99_5 = (int) underlying.getValueAtPercentile(99.5);\n        p99_9 = (int) underlying.getValueAtPercentile(99.9);\n        p99_95 = (int) underlying.getValueAtPercentile(99.95);\n        p99_99 = (int) underlying.getValueAtPercentile(99.99);\n        p100 = (int) underlying.getValueAtPercentile(100);\n\n        totalCount = underlying.getTotalCount();\n    }\n\n    /**\n     * Return the cached value only\n     * @return cached distribution mean\n     */\n    public int getMean() {\n        return mean;\n    }\n\n    /**\n     * Return the cached value if available.\n     * Otherwise, we need to synchronize access to the underlying {@link Histogram}\n     * @param percentile percentile of distribution\n     * @return value at percentile (from cache if possible)\n     */\n    public int getValueAtPercentile(double percentile) {\n        int permyriad = (int) (percentile * 100);\n        switch (permyriad) {\n            case 0: return p0;\n            case 500: return p5;\n            case 1000: return p10;\n            case 1500: return p15;\n            case 2000: return p20;\n            case 2500: return p25;\n            case 3000: return p30;\n            case 3500: return p35;\n            case 4000: return p40;\n            case 4500: return p45;\n            case 5000: return p50;\n            case 5500: return p55;\n            case 6000: return p60;\n            case 6500: return p65;\n            case 7000: return p70;\n            case 7500: return p75;\n            case 8000: return p80;\n            case 8500: return p85;\n            case 9000: return p90;\n            case 9500: return p95;\n            case 9900: return p99;\n            case 9950: return p99_5;\n            case 9990: return p99_9;\n            case 9995: return p99_95;\n            case 9999: return p99_99;\n            case 10000: return p100;\n            default: throw new IllegalArgumentException(\"Percentile (\" + percentile + \") is not currently cached\");\n        }\n    }\n\n    public long getTotalCount() {\n        return totalCount;\n    }\n\n    public static Histogram getNewHistogram() {\n        return new Histogram(NUMBER_SIGNIFICANT_DIGITS);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCollapserEvent.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixEventType;\n\n/**\n * Data class that comprises the event stream for Hystrix collapser executions.\n * This class represents the 3 things that can happen (found in {@link com.netflix.hystrix.HystrixEventType.Collapser} enum:\n * <p><ul>\n *     <li>ADDED_TO_BATCH</li>\n *     <li>BATCH_EXECUTED</li>\n *     <li>RESPONSE_FROM_CACHE</li>\n * </ul>\n *\n */\npublic class HystrixCollapserEvent implements HystrixEvent {\n    private final HystrixCollapserKey collapserKey;\n    private final HystrixEventType.Collapser eventType;\n    private final int count;\n\n    protected HystrixCollapserEvent(HystrixCollapserKey collapserKey, HystrixEventType.Collapser eventType, int count) {\n        this.collapserKey = collapserKey;\n        this.eventType = eventType;\n        this.count = count;\n    }\n\n    public static HystrixCollapserEvent from(HystrixCollapserKey collapserKey, HystrixEventType.Collapser eventType, int count) {\n        return new HystrixCollapserEvent(collapserKey, eventType, count);\n    }\n\n    public HystrixCollapserKey getCollapserKey() {\n        return collapserKey;\n    }\n\n    public HystrixEventType.Collapser getEventType() {\n        return eventType;\n    }\n\n    public int getCount() {\n        return count;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixCollapserEvent[\" + collapserKey.name() + \"] : \" + eventType.name() + \" : \" + count;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCollapserEventStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.SerializedSubject;\nimport rx.subjects.Subject;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Per-Collapser stream of {@link HystrixCollapserEvent}s.  This gets written to by {@link HystrixThreadEventStream}s.\n * Events are emitted synchronously in the same thread that performs the batch-command execution.\n */\npublic class HystrixCollapserEventStream implements HystrixEventStream<HystrixCollapserEvent> {\n    private final HystrixCollapserKey collapserKey;\n\n    private final Subject<HystrixCollapserEvent, HystrixCollapserEvent> writeOnlyStream;\n    private final Observable<HystrixCollapserEvent> readOnlyStream;\n\n    private static final ConcurrentMap<String, HystrixCollapserEventStream> streams = new ConcurrentHashMap<String, HystrixCollapserEventStream>();\n\n    public static HystrixCollapserEventStream getInstance(HystrixCollapserKey collapserKey) {\n        HystrixCollapserEventStream initialStream = streams.get(collapserKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (HystrixCollapserEventStream.class) {\n                HystrixCollapserEventStream existingStream = streams.get(collapserKey.name());\n                if (existingStream == null) {\n                    HystrixCollapserEventStream newStream = new HystrixCollapserEventStream(collapserKey);\n                    streams.putIfAbsent(collapserKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    HystrixCollapserEventStream(final HystrixCollapserKey collapserKey) {\n        this.collapserKey = collapserKey;\n\n        this.writeOnlyStream = new SerializedSubject<HystrixCollapserEvent, HystrixCollapserEvent>(PublishSubject.<HystrixCollapserEvent>create());\n        this.readOnlyStream = writeOnlyStream.share();\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public void write(HystrixCollapserEvent event) {\n        writeOnlyStream.onNext(event);\n    }\n\n    public Observable<HystrixCollapserEvent> observe() {\n        return readOnlyStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixCollapserEventStream(\" + collapserKey.name() + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCommandCompletion.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Data class which gets fed into event stream when a command completes (with any of the outcomes in {@link HystrixEventType}).\n */\npublic class HystrixCommandCompletion extends HystrixCommandEvent {\n    protected final ExecutionResult executionResult;\n    protected final HystrixRequestContext requestContext;\n\n    private final static HystrixEventType[] ALL_EVENT_TYPES = HystrixEventType.values();\n\n    HystrixCommandCompletion(ExecutionResult executionResult, HystrixCommandKey commandKey,\n                             HystrixThreadPoolKey threadPoolKey, HystrixRequestContext requestContext) {\n        super(commandKey, threadPoolKey);\n        this.executionResult = executionResult;\n        this.requestContext = requestContext;\n    }\n\n    public static HystrixCommandCompletion from(ExecutionResult executionResult, HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey) {\n        return from(executionResult, commandKey, threadPoolKey, HystrixRequestContext.getContextForCurrentThread());\n    }\n\n    public static HystrixCommandCompletion from(ExecutionResult executionResult, HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey, HystrixRequestContext requestContext) {\n        return new HystrixCommandCompletion(executionResult, commandKey, threadPoolKey, requestContext);\n    }\n\n    @Override\n    public boolean isResponseThreadPoolRejected() {\n        return executionResult.isResponseThreadPoolRejected();\n    }\n\n    @Override\n    public boolean isExecutionStart() {\n        return false;\n    }\n\n    @Override\n    public boolean isExecutedInThread() {\n        return executionResult.isExecutedInThread();\n    }\n\n    @Override\n    public boolean isCommandCompletion() {\n        return true;\n    }\n\n    public HystrixRequestContext getRequestContext() {\n        return this.requestContext;\n    }\n\n    public ExecutionResult.EventCounts getEventCounts() {\n        return executionResult.getEventCounts();\n    }\n\n    public long getExecutionLatency() {\n        return executionResult.getExecutionLatency();\n    }\n\n    public long getTotalLatency() {\n        return executionResult.getUserThreadLatency();\n    }\n\n    @Override\n    public boolean didCommandExecute() {\n        return executionResult.executionOccurred();\n    }\n\n    @Override\n    public String toString() {\n        StringBuffer sb = new StringBuffer();\n        List<HystrixEventType> foundEventTypes = new ArrayList<HystrixEventType>();\n\n        sb.append(getCommandKey().name()).append(\"[\");\n        for (HystrixEventType eventType: ALL_EVENT_TYPES) {\n            if (executionResult.getEventCounts().contains(eventType)) {\n                foundEventTypes.add(eventType);\n            }\n        }\n        int i = 0;\n        for (HystrixEventType eventType: foundEventTypes) {\n            sb.append(eventType.name());\n            int eventCount = executionResult.getEventCounts().getCount(eventType);\n            if (eventCount > 1) {\n                sb.append(\"x\").append(eventCount);\n\n            }\n            if (i < foundEventTypes.size() - 1) {\n                sb.append(\", \");\n            }\n            i++;\n        }\n        sb.append(\"][\").append(getExecutionLatency()).append(\" ms]\");\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCommandCompletionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.SerializedSubject;\nimport rx.subjects.Subject;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Per-Command stream of {@link HystrixCommandCompletion}s.  This gets written to by {@link HystrixThreadEventStream}s.\n * Events are emitted synchronously in the same thread that performs the command execution.\n */\npublic class HystrixCommandCompletionStream implements HystrixEventStream<HystrixCommandCompletion> {\n    private final HystrixCommandKey commandKey;\n\n    private final Subject<HystrixCommandCompletion, HystrixCommandCompletion> writeOnlySubject;\n    private final Observable<HystrixCommandCompletion> readOnlyStream;\n\n    private static final ConcurrentMap<String, HystrixCommandCompletionStream> streams = new ConcurrentHashMap<String, HystrixCommandCompletionStream>();\n\n    public static HystrixCommandCompletionStream getInstance(HystrixCommandKey commandKey) {\n        HystrixCommandCompletionStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (HystrixCommandCompletionStream.class) {\n                HystrixCommandCompletionStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    HystrixCommandCompletionStream newStream = new HystrixCommandCompletionStream(commandKey);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    HystrixCommandCompletionStream(final HystrixCommandKey commandKey) {\n        this.commandKey = commandKey;\n\n        this.writeOnlySubject = new SerializedSubject<HystrixCommandCompletion, HystrixCommandCompletion>(PublishSubject.<HystrixCommandCompletion>create());\n        this.readOnlyStream = writeOnlySubject.share();\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public void write(HystrixCommandCompletion event) {\n        writeOnlySubject.onNext(event);\n    }\n\n\n    @Override\n    public Observable<HystrixCommandCompletion> observe() {\n        return readOnlyStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixCommandCompletionStream(\" + commandKey.name() + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCommandEvent.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport rx.functions.Func1;\n\n/**\n * Data class that comprises the event stream for Hystrix command executions.\n * As of 1.5.0-RC1, this is only {@link HystrixCommandCompletion}s.\n */\npublic abstract class HystrixCommandEvent implements HystrixEvent {\n    private final HystrixCommandKey commandKey;\n    private final HystrixThreadPoolKey threadPoolKey;\n\n    protected HystrixCommandEvent(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey) {\n        this.commandKey = commandKey;\n        this.threadPoolKey = threadPoolKey;\n    }\n\n    public HystrixCommandKey getCommandKey() {\n        return commandKey;\n    }\n\n    public HystrixThreadPoolKey getThreadPoolKey() {\n        return threadPoolKey;\n    }\n\n    public abstract boolean isExecutionStart();\n\n    public abstract boolean isExecutedInThread();\n\n    public abstract boolean isResponseThreadPoolRejected();\n\n    public abstract boolean isCommandCompletion();\n\n    public abstract boolean didCommandExecute();\n\n    public static final Func1<HystrixCommandEvent, Boolean> filterCompletionsOnly = new Func1<HystrixCommandEvent, Boolean>() {\n        @Override\n        public Boolean call(HystrixCommandEvent commandEvent) {\n            return commandEvent.isCommandCompletion();\n        }\n    };\n\n    public static final Func1<HystrixCommandEvent, Boolean> filterActualExecutions = new Func1<HystrixCommandEvent, Boolean>() {\n        @Override\n        public Boolean call(HystrixCommandEvent commandEvent) {\n            return commandEvent.didCommandExecute();\n        }\n    };\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCommandExecutionStarted.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\n\n/**\n * Data class that get fed to event stream when a command starts executing.\n */\npublic class HystrixCommandExecutionStarted extends HystrixCommandEvent {\n    private final HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy;\n    private final int currentConcurrency;\n\n    public HystrixCommandExecutionStarted(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey,\n                                          HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy,\n                                          int currentConcurrency) {\n        super(commandKey, threadPoolKey);\n        this.isolationStrategy = isolationStrategy;\n        this.currentConcurrency = currentConcurrency;\n    }\n\n    @Override\n    public boolean isExecutionStart() {\n        return true;\n    }\n\n    @Override\n    public boolean isExecutedInThread() {\n        return isolationStrategy == HystrixCommandProperties.ExecutionIsolationStrategy.THREAD;\n    }\n\n    @Override\n    public boolean isResponseThreadPoolRejected() {\n        return false;\n    }\n\n    @Override\n    public boolean isCommandCompletion() {\n        return false;\n    }\n\n    @Override\n    public boolean didCommandExecute() {\n        return false;\n    }\n\n    public int getCurrentConcurrency() {\n        return currentConcurrency;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixCommandStartStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.SerializedSubject;\nimport rx.subjects.Subject;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Per-Command stream of {@link HystrixCommandExecutionStarted}s.  This gets written to by {@link HystrixThreadEventStream}s.\n * Events are emitted synchronously in the same thread that performs the command execution.\n */\npublic class HystrixCommandStartStream implements HystrixEventStream<HystrixCommandExecutionStarted> {\n    private final HystrixCommandKey commandKey;\n\n    private final Subject<HystrixCommandExecutionStarted, HystrixCommandExecutionStarted> writeOnlySubject;\n    private final Observable<HystrixCommandExecutionStarted> readOnlyStream;\n\n    private static final ConcurrentMap<String, HystrixCommandStartStream> streams = new ConcurrentHashMap<String, HystrixCommandStartStream>();\n\n    public static HystrixCommandStartStream getInstance(HystrixCommandKey commandKey) {\n        HystrixCommandStartStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (HystrixCommandStartStream.class) {\n                HystrixCommandStartStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    HystrixCommandStartStream newStream = new HystrixCommandStartStream(commandKey);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    HystrixCommandStartStream(final HystrixCommandKey commandKey) {\n        this.commandKey = commandKey;\n\n        this.writeOnlySubject = new SerializedSubject<HystrixCommandExecutionStarted, HystrixCommandExecutionStarted>(PublishSubject.<HystrixCommandExecutionStarted>create());\n        this.readOnlyStream = writeOnlySubject.share();\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public void write(HystrixCommandExecutionStarted event) {\n        writeOnlySubject.onNext(event);\n    }\n\n    @Override\n    public Observable<HystrixCommandExecutionStarted> observe() {\n        return readOnlyStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixCommandStartStream(\" + commandKey.name() + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixEvent.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\n/**\n * Marker interface for events which may appear in an event stream\n */\npublic interface HystrixEvent {\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixEventStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport rx.Observable;\n\n/**\n * Base interface for a stream of {@link com.netflix.hystrix.HystrixEventType}s.  Allows consumption by individual\n * {@link com.netflix.hystrix.HystrixEventType} or by time-based bucketing of events\n */\npublic interface HystrixEventStream<E extends HystrixEvent> {\n\n    Observable<E> observe();\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixRequestEvents.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixInvokableInfo;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class HystrixRequestEvents {\n    private final Collection<HystrixInvokableInfo<?>> executions;\n\n    public HystrixRequestEvents(Collection<HystrixInvokableInfo<?>> executions) {\n        this.executions = executions;\n    }\n\n    public Collection<HystrixInvokableInfo<?>> getExecutions() {\n        return executions;\n    }\n\n    public Map<ExecutionSignature, List<Integer>> getExecutionsMappedToLatencies() {\n        Map<CommandAndCacheKey, Integer> cachingDetector = new HashMap<CommandAndCacheKey, Integer>();\n        List<HystrixInvokableInfo<?>> nonCachedExecutions = new ArrayList<HystrixInvokableInfo<?>>(executions.size());\n        for (HystrixInvokableInfo<?> execution: executions) {\n            if (execution.getPublicCacheKey() != null) {\n                //eligible for caching - might be the initial, or might be from cache\n                CommandAndCacheKey key = new CommandAndCacheKey(execution.getCommandKey().name(), execution.getPublicCacheKey());\n                Integer count = cachingDetector.get(key);\n                if (count != null) {\n                    //key already seen\n                    cachingDetector.put(key, count + 1);\n                } else {\n                    //key not seen yet\n                    cachingDetector.put(key, 0);\n                }\n            }\n            if (!execution.isResponseFromCache()) {\n                nonCachedExecutions.add(execution);\n            }\n        }\n\n        Map<ExecutionSignature, List<Integer>> commandDeduper = new HashMap<ExecutionSignature, List<Integer>>();\n        for (HystrixInvokableInfo<?> execution: nonCachedExecutions) {\n            int cachedCount = 0;\n            String cacheKey = execution.getPublicCacheKey();\n            if (cacheKey != null) {\n                CommandAndCacheKey key = new CommandAndCacheKey(execution.getCommandKey().name(), cacheKey);\n                cachedCount = cachingDetector.get(key);\n            }\n            ExecutionSignature signature;\n            if (cachedCount > 0) {\n                //this has a RESPONSE_FROM_CACHE and needs to get split off\n                signature = ExecutionSignature.from(execution, cacheKey, cachedCount);\n            } else {\n                //nothing cached from this, can collapse further\n                signature = ExecutionSignature.from(execution);\n            }\n            List<Integer> currentLatencyList = commandDeduper.get(signature);\n            if (currentLatencyList != null) {\n                currentLatencyList.add(execution.getExecutionTimeInMilliseconds());\n            } else {\n                List<Integer> newLatencyList = new ArrayList<Integer>();\n                newLatencyList.add(execution.getExecutionTimeInMilliseconds());\n                commandDeduper.put(signature, newLatencyList);\n            }\n        }\n\n        return commandDeduper;\n    }\n\n    private static class CommandAndCacheKey {\n        private final String commandName;\n        private final String cacheKey;\n\n        public CommandAndCacheKey(String commandName, String cacheKey) {\n            this.commandName = commandName;\n            this.cacheKey = cacheKey;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            CommandAndCacheKey that = (CommandAndCacheKey) o;\n\n            if (!commandName.equals(that.commandName)) return false;\n            return cacheKey.equals(that.cacheKey);\n\n        }\n\n        @Override\n        public int hashCode() {\n            int result = commandName.hashCode();\n            result = 31 * result + cacheKey.hashCode();\n            return result;\n        }\n\n        @Override\n        public String toString() {\n            return \"CommandAndCacheKey{\" +\n                    \"commandName='\" + commandName + '\\'' +\n                    \", cacheKey='\" + cacheKey + '\\'' +\n                    '}';\n        }\n    }\n\n    public static class ExecutionSignature {\n        private final String commandName;\n        private final ExecutionResult.EventCounts eventCounts;\n        private final String cacheKey;\n        private final int cachedCount;\n        private final HystrixCollapserKey collapserKey;\n        private final int collapserBatchSize;\n\n        private ExecutionSignature(HystrixCommandKey commandKey, ExecutionResult.EventCounts eventCounts, String cacheKey, int cachedCount, HystrixCollapserKey collapserKey, int collapserBatchSize) {\n            this.commandName = commandKey.name();\n            this.eventCounts = eventCounts;\n            this.cacheKey = cacheKey;\n            this.cachedCount = cachedCount;\n            this.collapserKey = collapserKey;\n            this.collapserBatchSize = collapserBatchSize;\n        }\n\n        public static ExecutionSignature from(HystrixInvokableInfo<?> execution) {\n            return new ExecutionSignature(execution.getCommandKey(), execution.getEventCounts(), null, 0, execution.getOriginatingCollapserKey(), execution.getNumberCollapsed());\n        }\n\n        public static ExecutionSignature from(HystrixInvokableInfo<?> execution, String cacheKey, int cachedCount) {\n            return new ExecutionSignature(execution.getCommandKey(), execution.getEventCounts(), cacheKey, cachedCount, execution.getOriginatingCollapserKey(), execution.getNumberCollapsed());\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            ExecutionSignature that = (ExecutionSignature) o;\n\n            if (!commandName.equals(that.commandName)) return false;\n            if (!eventCounts.equals(that.eventCounts)) return false;\n            return !(cacheKey != null ? !cacheKey.equals(that.cacheKey) : that.cacheKey != null);\n\n        }\n\n        @Override\n        public int hashCode() {\n            int result = commandName.hashCode();\n            result = 31 * result + eventCounts.hashCode();\n            result = 31 * result + (cacheKey != null ? cacheKey.hashCode() : 0);\n            return result;\n        }\n\n        public String getCommandName() {\n            return commandName;\n        }\n\n        public ExecutionResult.EventCounts getEventCounts() {\n            return eventCounts;\n        }\n\n        public int getCachedCount() {\n            return cachedCount;\n        }\n\n\n        public HystrixCollapserKey getCollapserKey() {\n            return collapserKey;\n        }\n\n        public int getCollapserBatchSize() {\n            return collapserBatchSize;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixRequestEventsStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.Subject;\n\nimport java.util.Collection;\n\n/**\n * Stream of requests, each of which contains a series of command executions\n */\npublic class HystrixRequestEventsStream {\n    private final Subject<HystrixRequestEvents, HystrixRequestEvents> writeOnlyRequestEventsSubject;\n    private final Observable<HystrixRequestEvents> readOnlyRequestEvents;\n\n    /* package */ HystrixRequestEventsStream() {\n        writeOnlyRequestEventsSubject = PublishSubject.create();\n        readOnlyRequestEvents = writeOnlyRequestEventsSubject.onBackpressureBuffer(1024);\n    }\n\n    private static final HystrixRequestEventsStream INSTANCE = new HystrixRequestEventsStream();\n\n    public static HystrixRequestEventsStream getInstance() {\n        return INSTANCE;\n    }\n\n    public void shutdown() {\n        writeOnlyRequestEventsSubject.onCompleted();\n    }\n\n    public void write(Collection<HystrixInvokableInfo<?>> executions) {\n        HystrixRequestEvents requestEvents = new HystrixRequestEvents(executions);\n        writeOnlyRequestEventsSubject.onNext(requestEvents);\n    }\n\n    public Observable<HystrixRequestEvents> observe() {\n        return readOnlyRequestEvents;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixThreadEventStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport rx.functions.Action1;\nimport rx.observers.Subscribers;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.Subject;\n\n/**\n * Per-thread event stream.  No synchronization required when writing to it since it's single-threaded.\n *\n * Some threads will be dedicated to a single HystrixCommandKey (a member of a thread-isolated {@link HystrixThreadPool}.\n * However, many situations arise where a single thread may serve many different commands.  Examples include:\n * * Application caller threads (semaphore-isolated commands, or thread-pool-rejections)\n * * Timer threads (timeouts or collapsers)\n * <p>\n * I don't think that a thread-level view is an interesting one to consume (I could be wrong), so at the moment there\n * is no public way to consume it.  I can always add it later, if desired.\n * <p>\n * Instead, this stream writes to the following streams, which have more meaning to metrics consumers:\n * <ul>\n *     <li>{@link HystrixCommandCompletionStream}</li>\n *     <li>{@link HystrixCommandStartStream}</li>\n *     <li>{@link HystrixThreadPoolCompletionStream}</li>\n *     <li>{@link HystrixThreadPoolStartStream}</li>\n *     <li>{@link HystrixCollapserEventStream}</li>\n * </ul>\n *\n * Also note that any observers of this stream do so on the thread that writes the metric.  This is the command caller\n * thread in the SEMAPHORE-isolated case, and the Hystrix thread in the THREAD-isolated case. I determined this to\n * be more efficient CPU-wise than immediately hopping off-thread and doing all the metric calculations in the\n * RxComputationThreadPool.\n */\npublic class HystrixThreadEventStream {\n    private final long threadId;\n    private final String threadName;\n\n    private final Subject<HystrixCommandExecutionStarted, HystrixCommandExecutionStarted> writeOnlyCommandStartSubject;\n    private final Subject<HystrixCommandCompletion, HystrixCommandCompletion> writeOnlyCommandCompletionSubject;\n    private final Subject<HystrixCollapserEvent, HystrixCollapserEvent> writeOnlyCollapserSubject;\n\n    private static final ThreadLocal<HystrixThreadEventStream> threadLocalStreams = new ThreadLocal<HystrixThreadEventStream>() {\n        @Override\n        protected HystrixThreadEventStream initialValue() {\n            return new HystrixThreadEventStream(Thread.currentThread());\n        }\n    };\n\n    private static final Action1<HystrixCommandExecutionStarted> writeCommandStartsToShardedStreams = new Action1<HystrixCommandExecutionStarted>() {\n        @Override\n        public void call(HystrixCommandExecutionStarted event) {\n            HystrixCommandStartStream commandStartStream = HystrixCommandStartStream.getInstance(event.getCommandKey());\n            commandStartStream.write(event);\n\n            if (event.isExecutedInThread()) {\n                HystrixThreadPoolStartStream threadPoolStartStream = HystrixThreadPoolStartStream.getInstance(event.getThreadPoolKey());\n                threadPoolStartStream.write(event);\n            }\n        }\n    };\n\n    private static final Action1<HystrixCommandCompletion> writeCommandCompletionsToShardedStreams = new Action1<HystrixCommandCompletion>() {\n        @Override\n        public void call(HystrixCommandCompletion commandCompletion) {\n            HystrixCommandCompletionStream commandStream = HystrixCommandCompletionStream.getInstance(commandCompletion.getCommandKey());\n            commandStream.write(commandCompletion);\n\n            if (commandCompletion.isExecutedInThread() || commandCompletion.isResponseThreadPoolRejected()) {\n                HystrixThreadPoolCompletionStream threadPoolStream = HystrixThreadPoolCompletionStream.getInstance(commandCompletion.getThreadPoolKey());\n                threadPoolStream.write(commandCompletion);\n            }\n        }\n    };\n\n    private static final Action1<HystrixCollapserEvent> writeCollapserExecutionsToShardedStreams = new Action1<HystrixCollapserEvent>() {\n        @Override\n        public void call(HystrixCollapserEvent collapserEvent) {\n            HystrixCollapserEventStream collapserStream = HystrixCollapserEventStream.getInstance(collapserEvent.getCollapserKey());\n            collapserStream.write(collapserEvent);\n        }\n    };\n\n    /* package */ HystrixThreadEventStream(Thread thread) {\n        this.threadId = thread.getId();\n        this.threadName = thread.getName();\n        writeOnlyCommandStartSubject = PublishSubject.create();\n        writeOnlyCommandCompletionSubject = PublishSubject.create();\n        writeOnlyCollapserSubject = PublishSubject.create();\n\n        writeOnlyCommandStartSubject\n                .onBackpressureBuffer()\n                .doOnNext(writeCommandStartsToShardedStreams)\n                .unsafeSubscribe(Subscribers.empty());\n\n        writeOnlyCommandCompletionSubject\n                .onBackpressureBuffer()\n                .doOnNext(writeCommandCompletionsToShardedStreams)\n                .unsafeSubscribe(Subscribers.empty());\n\n        writeOnlyCollapserSubject\n                .onBackpressureBuffer()\n                .doOnNext(writeCollapserExecutionsToShardedStreams)\n                .unsafeSubscribe(Subscribers.empty());\n    }\n\n    public static HystrixThreadEventStream getInstance() {\n        return threadLocalStreams.get();\n    }\n\n    public void shutdown() {\n        writeOnlyCommandStartSubject.onCompleted();\n        writeOnlyCommandCompletionSubject.onCompleted();\n        writeOnlyCollapserSubject.onCompleted();\n    }\n\n    public void commandExecutionStarted(HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey,\n                                        HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy, int currentConcurrency) {\n        HystrixCommandExecutionStarted event = new HystrixCommandExecutionStarted(commandKey, threadPoolKey, isolationStrategy, currentConcurrency);\n        writeOnlyCommandStartSubject.onNext(event);\n    }\n\n    public void executionDone(ExecutionResult executionResult, HystrixCommandKey commandKey, HystrixThreadPoolKey threadPoolKey) {\n        HystrixCommandCompletion event = HystrixCommandCompletion.from(executionResult, commandKey, threadPoolKey);\n        writeOnlyCommandCompletionSubject.onNext(event);\n    }\n\n    public void collapserResponseFromCache(HystrixCollapserKey collapserKey) {\n        HystrixCollapserEvent collapserEvent = HystrixCollapserEvent.from(collapserKey, HystrixEventType.Collapser.RESPONSE_FROM_CACHE, 1);\n        writeOnlyCollapserSubject.onNext(collapserEvent);\n    }\n\n    public void collapserBatchExecuted(HystrixCollapserKey collapserKey, int batchSize) {\n        HystrixCollapserEvent batchExecution = HystrixCollapserEvent.from(collapserKey, HystrixEventType.Collapser.BATCH_EXECUTED, 1);\n        HystrixCollapserEvent batchAdditions = HystrixCollapserEvent.from(collapserKey, HystrixEventType.Collapser.ADDED_TO_BATCH, batchSize);\n        writeOnlyCollapserSubject.onNext(batchExecution);\n        writeOnlyCollapserSubject.onNext(batchAdditions);\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixThreadEventStream (\" + threadId + \" - \" + threadName + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixThreadPoolCompletionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.SerializedSubject;\nimport rx.subjects.Subject;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Per-ThreadPool stream of {@link HystrixCommandCompletion}s.  This gets written to by {@link HystrixThreadEventStream}s.\n * Events are emitted synchronously in the same thread that performs the command execution.\n */\npublic class HystrixThreadPoolCompletionStream implements HystrixEventStream<HystrixCommandCompletion> {\n\n    private final HystrixThreadPoolKey threadPoolKey;\n\n    private final Subject<HystrixCommandCompletion, HystrixCommandCompletion> writeOnlySubject;\n    private final Observable<HystrixCommandCompletion> readOnlyStream;\n\n    private static final ConcurrentMap<String, HystrixThreadPoolCompletionStream> streams = new ConcurrentHashMap<String, HystrixThreadPoolCompletionStream>();\n\n    public static HystrixThreadPoolCompletionStream getInstance(HystrixThreadPoolKey threadPoolKey) {\n        HystrixThreadPoolCompletionStream initialStream = streams.get(threadPoolKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (HystrixThreadPoolCompletionStream.class) {\n                HystrixThreadPoolCompletionStream existingStream = streams.get(threadPoolKey.name());\n                if (existingStream == null) {\n                    HystrixThreadPoolCompletionStream newStream = new HystrixThreadPoolCompletionStream(threadPoolKey);\n                    streams.putIfAbsent(threadPoolKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    HystrixThreadPoolCompletionStream(final HystrixThreadPoolKey threadPoolKey) {\n        this.threadPoolKey = threadPoolKey;\n\n        this.writeOnlySubject = new SerializedSubject<HystrixCommandCompletion, HystrixCommandCompletion>(PublishSubject.<HystrixCommandCompletion>create());\n        this.readOnlyStream = writeOnlySubject.share();\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public void write(HystrixCommandCompletion event) {\n        writeOnlySubject.onNext(event);\n    }\n\n    @Override\n    public Observable<HystrixCommandCompletion> observe() {\n        return readOnlyStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixThreadPoolCompletionStream(\" + threadPoolKey.name() + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/HystrixThreadPoolStartStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\nimport rx.subjects.SerializedSubject;\nimport rx.subjects.Subject;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Per-ThreadPool stream of {@link HystrixCommandExecutionStarted}s.  This gets written to by {@link HystrixThreadEventStream}s.\n * Events are emitted synchronously in the same thread that performs the command execution.\n */\npublic class HystrixThreadPoolStartStream implements HystrixEventStream<HystrixCommandExecutionStarted> {\n\n    private final HystrixThreadPoolKey threadPoolKey;\n\n    private final Subject<HystrixCommandExecutionStarted, HystrixCommandExecutionStarted> writeOnlySubject;\n    private final Observable<HystrixCommandExecutionStarted> readOnlyStream;\n\n    private static final ConcurrentMap<String, HystrixThreadPoolStartStream> streams = new ConcurrentHashMap<String, HystrixThreadPoolStartStream>();\n\n    public static HystrixThreadPoolStartStream getInstance(HystrixThreadPoolKey threadPoolKey) {\n        HystrixThreadPoolStartStream initialStream = streams.get(threadPoolKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (HystrixThreadPoolStartStream.class) {\n                HystrixThreadPoolStartStream existingStream = streams.get(threadPoolKey.name());\n                if (existingStream == null) {\n                    HystrixThreadPoolStartStream newStream = new HystrixThreadPoolStartStream(threadPoolKey);\n                    streams.putIfAbsent(threadPoolKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    HystrixThreadPoolStartStream(final HystrixThreadPoolKey threadPoolKey) {\n        this.threadPoolKey = threadPoolKey;\n\n        this.writeOnlySubject = new SerializedSubject<HystrixCommandExecutionStarted, HystrixCommandExecutionStarted>(PublishSubject.<HystrixCommandExecutionStarted>create());\n        this.readOnlyStream = writeOnlySubject.share();\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public void write(HystrixCommandExecutionStarted event) {\n        writeOnlySubject.onNext(event);\n    }\n\n    @Override\n    public Observable<HystrixCommandExecutionStarted> observe() {\n        return readOnlyStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"HystrixThreadPoolStartStream(\" + threadPoolKey.name() + \")\";\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/BucketedCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.metric.HystrixEvent;\nimport com.netflix.hystrix.metric.HystrixEventStream;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.subjects.BehaviorSubject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Abstract class that imposes a bucketing structure and provides streams of buckets\n *\n * @param <Event> type of raw data that needs to get summarized into a bucket\n * @param <Bucket> type of data contained in each bucket\n * @param <Output> type of data emitted to stream subscribers (often is the same as A but does not have to be)\n */\npublic abstract class BucketedCounterStream<Event extends HystrixEvent, Bucket, Output> {\n    protected final int numBuckets;\n    protected final Observable<Bucket> bucketedStream;\n    protected final AtomicReference<Subscription> subscription = new AtomicReference<Subscription>(null);\n\n    private final Func1<Observable<Event>, Observable<Bucket>> reduceBucketToSummary;\n\n    private final BehaviorSubject<Output> counterSubject = BehaviorSubject.create(getEmptyOutputValue());\n\n    protected BucketedCounterStream(final HystrixEventStream<Event> inputEventStream, final int numBuckets, final int bucketSizeInMs,\n                                    final Func2<Bucket, Event, Bucket> appendRawEventToBucket) {\n        this.numBuckets = numBuckets;\n        this.reduceBucketToSummary = new Func1<Observable<Event>, Observable<Bucket>>() {\n            @Override\n            public Observable<Bucket> call(Observable<Event> eventBucket) {\n                return eventBucket.reduce(getEmptyBucketSummary(), appendRawEventToBucket);\n            }\n        };\n\n        final List<Bucket> emptyEventCountsToStart = new ArrayList<Bucket>();\n        for (int i = 0; i < numBuckets; i++) {\n            emptyEventCountsToStart.add(getEmptyBucketSummary());\n        }\n\n        this.bucketedStream = Observable.defer(new Func0<Observable<Bucket>>() {\n            @Override\n            public Observable<Bucket> call() {\n                return inputEventStream\n                        .observe()\n                        .window(bucketSizeInMs, TimeUnit.MILLISECONDS) //bucket it by the counter window so we can emit to the next operator in time chunks, not on every OnNext\n                        .flatMap(reduceBucketToSummary)                //for a given bucket, turn it into a long array containing counts of event types\n                        .startWith(emptyEventCountsToStart);           //start it with empty arrays to make consumer logic as generic as possible (windows are always full)\n            }\n        });\n    }\n\n    abstract Bucket getEmptyBucketSummary();\n\n    abstract Output getEmptyOutputValue();\n\n    /**\n     * Return the stream of buckets\n     * @return stream of buckets\n     */\n    public abstract Observable<Output> observe();\n\n    public void startCachingStreamValuesIfUnstarted() {\n        if (subscription.get() == null) {\n            //the stream is not yet started\n            Subscription candidateSubscription = observe().subscribe(counterSubject);\n            if (subscription.compareAndSet(null, candidateSubscription)) {\n                //won the race to set the subscription\n            } else {\n                //lost the race to set the subscription, so we need to cancel this one\n                candidateSubscription.unsubscribe();\n            }\n        }\n    }\n\n    /**\n     * Synchronous call to retrieve the last calculated bucket without waiting for any emissions\n     * @return last calculated bucket\n     */\n    public Output getLatest() {\n        startCachingStreamValuesIfUnstarted();\n        if (counterSubject.hasValue()) {\n            return counterSubject.getValue();\n        } else {\n            return getEmptyOutputValue();\n        }\n    }\n\n    public void unsubscribe() {\n        Subscription s = subscription.get();\n        if (s != null) {\n            s.unsubscribe();\n            subscription.compareAndSet(s, null);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/BucketedCumulativeCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.metric.HystrixEvent;\nimport com.netflix.hystrix.metric.HystrixEventStream;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Refinement of {@link BucketedCounterStream} which accumulates counters infinitely in the bucket-reduction step\n *\n * @param <Event> type of raw data that needs to get summarized into a bucket\n * @param <Bucket> type of data contained in each bucket\n * @param <Output> type of data emitted to stream subscribers (often is the same as A but does not have to be)\n */\npublic abstract class BucketedCumulativeCounterStream<Event extends HystrixEvent, Bucket, Output> extends BucketedCounterStream<Event, Bucket, Output> {\n    private Observable<Output> sourceStream;\n    private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);\n\n    protected BucketedCumulativeCounterStream(HystrixEventStream<Event> stream, int numBuckets, int bucketSizeInMs,\n                                              Func2<Bucket, Event, Bucket> reduceCommandCompletion,\n                                              Func2<Output, Bucket, Output> reduceBucket) {\n        super(stream, numBuckets, bucketSizeInMs, reduceCommandCompletion);\n\n        this.sourceStream = bucketedStream\n                .scan(getEmptyOutputValue(), reduceBucket)\n                .skip(numBuckets)\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(true);\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(false);\n                    }\n                })\n                .share()                        //multiple subscribers should get same data\n                .onBackpressureDrop();          //if there are slow consumers, data should not buffer\n    }\n\n    @Override\n    public Observable<Output> observe() {\n        return sourceStream;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/BucketedRollingCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.metric.HystrixEvent;\nimport com.netflix.hystrix.metric.HystrixEventStream;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Refinement of {@link BucketedCounterStream} which reduces numBuckets at a time.\n *\n * @param <Event> type of raw data that needs to get summarized into a bucket\n * @param <Bucket> type of data contained in each bucket\n * @param <Output> type of data emitted to stream subscribers (often is the same as A but does not have to be)\n */\npublic abstract class BucketedRollingCounterStream<Event extends HystrixEvent, Bucket, Output> extends BucketedCounterStream<Event, Bucket, Output> {\n    private Observable<Output> sourceStream;\n    private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);\n\n    protected BucketedRollingCounterStream(HystrixEventStream<Event> stream, final int numBuckets, int bucketSizeInMs,\n                                           final Func2<Bucket, Event, Bucket> appendRawEventToBucket,\n                                           final Func2<Output, Bucket, Output> reduceBucket) {\n        super(stream, numBuckets, bucketSizeInMs, appendRawEventToBucket);\n        Func1<Observable<Bucket>, Observable<Output>> reduceWindowToSummary = new Func1<Observable<Bucket>, Observable<Output>>() {\n            @Override\n            public Observable<Output> call(Observable<Bucket> window) {\n                return window.scan(getEmptyOutputValue(), reduceBucket).skip(numBuckets);\n            }\n        };\n        this.sourceStream = bucketedStream      //stream broken up into buckets\n                .window(numBuckets, 1)          //emit overlapping windows of buckets\n                .flatMap(reduceWindowToSummary) //convert a window of bucket-summaries into a single summary\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(true);\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(false);\n                    }\n                })\n                .share()                        //multiple subscribers should get same data\n                .onBackpressureDrop();          //if there are slow consumers, data should not buffer\n    }\n\n    @Override\n    public Observable<Output> observe() {\n        return sourceStream;\n    }\n\n    /* package-private */ boolean isSourceCurrentlySubscribed() {\n        return isSourceCurrentlySubscribed.get();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/CumulativeCollapserEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixCollapserEvent;\nimport com.netflix.hystrix.metric.HystrixCollapserEventStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given Command.\n * There is no rolling window abstraction on this stream - every event since the start of the JVM is kept track of.\n * The event counters object is calculated on the same schedule as the rolling abstract {@link RollingCommandEventCounterStream},\n * so bucket rolls correspond to new data in this stream, though data never goes out of window in this stream.\n *\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link com.netflix.hystrix.HystrixCollapserProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link com.netflix.hystrix.HystrixCollapserProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.  This value (the latest observed value) may be queried using {@link #getLatest(HystrixEventType.Collapser)}.\n */\npublic class CumulativeCollapserEventCounterStream extends BucketedCumulativeCounterStream<HystrixCollapserEvent, long[], long[]> {\n\n    private static final ConcurrentMap<String, CumulativeCollapserEventCounterStream> streams = new ConcurrentHashMap<String, CumulativeCollapserEventCounterStream>();\n\n    private static final int NUM_EVENT_TYPES = HystrixEventType.Collapser.values().length;\n\n    public static CumulativeCollapserEventCounterStream getInstance(HystrixCollapserKey collapserKey, HystrixCollapserProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(collapserKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static CumulativeCollapserEventCounterStream getInstance(HystrixCollapserKey collapserKey, int numBuckets, int bucketSizeInMs) {\n        CumulativeCollapserEventCounterStream initialStream = streams.get(collapserKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (CumulativeCollapserEventCounterStream.class) {\n                CumulativeCollapserEventCounterStream existingStream = streams.get(collapserKey.name());\n                if (existingStream == null) {\n                    CumulativeCollapserEventCounterStream newStream = new CumulativeCollapserEventCounterStream(collapserKey, numBuckets, bucketSizeInMs, HystrixCollapserMetrics.appendEventToBucket, HystrixCollapserMetrics.bucketAggregator);\n                    streams.putIfAbsent(collapserKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private CumulativeCollapserEventCounterStream(HystrixCollapserKey collapserKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                                Func2<long[], HystrixCollapserEvent, long[]> appendEventToBucket,\n                                                Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixCollapserEventStream.getInstance(collapserKey), numCounterBuckets, counterBucketSizeInMs, appendEventToBucket, reduceBucket);\n    }\n\n    @Override\n    long[] getEmptyBucketSummary() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    @Override\n    long[] getEmptyOutputValue() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    public long getLatest(HystrixEventType.Collapser eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/CumulativeCommandEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given Command.\n * There is no rolling window abstraction on this stream - every event since the start of the JVM is kept track of.\n * The event counters object is calculated on the same schedule as the rolling abstract {@link RollingCommandEventCounterStream},\n * so bucket rolls correspond to new data in this stream, though data never goes out of window in this stream.\n *\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.  This value (the latest observed value) may be queried using {@link #getLatest(HystrixEventType)}.\n */\npublic class CumulativeCommandEventCounterStream extends BucketedCumulativeCounterStream<HystrixCommandCompletion, long[], long[]> {\n\n    private static final ConcurrentMap<String, CumulativeCommandEventCounterStream> streams = new ConcurrentHashMap<String, CumulativeCommandEventCounterStream>();\n\n    private static final int NUM_EVENT_TYPES = HystrixEventType.values().length;\n\n    public static CumulativeCommandEventCounterStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(commandKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static CumulativeCommandEventCounterStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        CumulativeCommandEventCounterStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (CumulativeCommandEventCounterStream.class) {\n                CumulativeCommandEventCounterStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    CumulativeCommandEventCounterStream newStream = new CumulativeCommandEventCounterStream(commandKey, numBuckets, bucketSizeInMs,\n                            HystrixCommandMetrics.appendEventToBucket, HystrixCommandMetrics.bucketAggregator);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private CumulativeCommandEventCounterStream(HystrixCommandKey commandKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                                Func2<long[], HystrixCommandCompletion, long[]> reduceCommandCompletion,\n                                                Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixCommandCompletionStream.getInstance(commandKey), numCounterBuckets, counterBucketSizeInMs, reduceCommandCompletion, reduceBucket);\n    }\n\n    @Override\n    long[] getEmptyBucketSummary() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    @Override\n    long[] getEmptyOutputValue() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    public long getLatest(HystrixEventType eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/CumulativeThreadPoolEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixThreadPoolCompletionStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given ThreadPool.\n * There is a rolling window abstraction on this stream.\n * The event counters object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.\n * You may query to find the latest rolling count of 2 events (executed/rejected) via {@link #getLatestCount(com.netflix.hystrix.HystrixEventType.ThreadPool)}.\n */\npublic class CumulativeThreadPoolEventCounterStream extends BucketedCumulativeCounterStream<HystrixCommandCompletion, long[], long[]> {\n\n    private static final ConcurrentMap<String, CumulativeThreadPoolEventCounterStream> streams = new ConcurrentHashMap<String, CumulativeThreadPoolEventCounterStream>();\n\n    private static final int ALL_EVENT_TYPES_SIZE = HystrixEventType.ThreadPool.values().length;\n\n    public static CumulativeThreadPoolEventCounterStream getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(threadPoolKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static CumulativeThreadPoolEventCounterStream getInstance(HystrixThreadPoolKey threadPoolKey, int numBuckets, int bucketSizeInMs) {\n        CumulativeThreadPoolEventCounterStream initialStream = streams.get(threadPoolKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (CumulativeThreadPoolEventCounterStream.class) {\n                CumulativeThreadPoolEventCounterStream existingStream = streams.get(threadPoolKey.name());\n                if (existingStream == null) {\n                    CumulativeThreadPoolEventCounterStream newStream =\n                            new CumulativeThreadPoolEventCounterStream(threadPoolKey, numBuckets, bucketSizeInMs,\n                                    HystrixThreadPoolMetrics.appendEventToBucket, HystrixThreadPoolMetrics.counterAggregator);\n                    streams.putIfAbsent(threadPoolKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n\n    private CumulativeThreadPoolEventCounterStream(HystrixThreadPoolKey threadPoolKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                                   Func2<long[], HystrixCommandCompletion, long[]> reduceCommandCompletion,\n                                                   Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixThreadPoolCompletionStream.getInstance(threadPoolKey), numCounterBuckets, counterBucketSizeInMs, reduceCommandCompletion, reduceBucket);\n    }\n\n    @Override\n    public long[] getEmptyBucketSummary() {\n        return new long[ALL_EVENT_TYPES_SIZE];\n    }\n\n    @Override\n    public long[] getEmptyOutputValue() {\n        return new long[ALL_EVENT_TYPES_SIZE];\n    }\n\n    public long getLatestCount(HystrixEventType.ThreadPool eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/HealthCountsStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of rolling health counts for a given Command.\n * There is a rolling window abstraction on this stream.\n * The HealthCounts object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new HealthCounts object is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsHealthSnapshotIntervalInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.  This value (the latest observed value) may be queried using {@link #getLatest()}.\n */\npublic class HealthCountsStream extends BucketedRollingCounterStream<HystrixCommandCompletion, long[], HystrixCommandMetrics.HealthCounts> {\n\n    private static final ConcurrentMap<String, HealthCountsStream> streams = new ConcurrentHashMap<String, HealthCountsStream>();\n\n    private static final int NUM_EVENT_TYPES = HystrixEventType.values().length;\n\n    private static final Func2<HystrixCommandMetrics.HealthCounts, long[], HystrixCommandMetrics.HealthCounts> healthCheckAccumulator = new Func2<HystrixCommandMetrics.HealthCounts, long[], HystrixCommandMetrics.HealthCounts>() {\n        @Override\n        public HystrixCommandMetrics.HealthCounts call(HystrixCommandMetrics.HealthCounts healthCounts, long[] bucketEventCounts) {\n            return healthCounts.plus(bucketEventCounts);\n        }\n    };\n\n\n    public static HealthCountsStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int healthCountBucketSizeInMs = properties.metricsHealthSnapshotIntervalInMilliseconds().get();\n        if (healthCountBucketSizeInMs == 0) {\n            throw new RuntimeException(\"You have set the bucket size to 0ms.  Please set a positive number, so that the metric stream can be properly consumed\");\n        }\n        final int numHealthCountBuckets = properties.metricsRollingStatisticalWindowInMilliseconds().get() / healthCountBucketSizeInMs;\n\n        return getInstance(commandKey, numHealthCountBuckets, healthCountBucketSizeInMs);\n    }\n\n    public static HealthCountsStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        HealthCountsStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            final HealthCountsStream healthStream;\n            synchronized (HealthCountsStream.class) {\n                HealthCountsStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    HealthCountsStream newStream = new HealthCountsStream(commandKey, numBuckets, bucketSizeInMs,\n                            HystrixCommandMetrics.appendEventToBucket);\n\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    healthStream = newStream;\n                } else {\n                    healthStream = existingStream;\n                }\n            }\n            healthStream.startCachingStreamValuesIfUnstarted();\n            return healthStream;\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public static void removeByKey(HystrixCommandKey key) {\n        streams.remove(key.name());\n    }\n\n    private HealthCountsStream(final HystrixCommandKey commandKey, final int numBuckets, final int bucketSizeInMs,\n                               Func2<long[], HystrixCommandCompletion, long[]> reduceCommandCompletion) {\n        super(HystrixCommandCompletionStream.getInstance(commandKey), numBuckets, bucketSizeInMs, reduceCommandCompletion, healthCheckAccumulator);\n    }\n\n    @Override\n    long[] getEmptyBucketSummary() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    @Override\n    HystrixCommandMetrics.HealthCounts getEmptyOutputValue() {\n        return HystrixCommandMetrics.HealthCounts.empty();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/HystrixDashboardStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\n\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class HystrixDashboardStream {\n    final int delayInMs;\n    final Observable<DashboardData> singleSource;\n    final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);\n\n    private static final DynamicIntProperty dataEmissionIntervalInMs =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.stream.dashboard.intervalInMilliseconds\", 500);\n\n    private HystrixDashboardStream(int delayInMs) {\n        this.delayInMs = delayInMs;\n        this.singleSource = Observable.interval(delayInMs, TimeUnit.MILLISECONDS)\n                .map(new Func1<Long, DashboardData>() {\n                    @Override\n                    public DashboardData call(Long timestamp) {\n                        return new DashboardData(\n                                HystrixCommandMetrics.getInstances(),\n                                HystrixThreadPoolMetrics.getInstances(),\n                                HystrixCollapserMetrics.getInstances()\n                        );\n                    }\n                })\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(true);\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(false);\n                    }\n                })\n                .share()\n                .onBackpressureDrop();\n    }\n\n    //The data emission interval is looked up on startup only\n    private static final HystrixDashboardStream INSTANCE =\n            new HystrixDashboardStream(dataEmissionIntervalInMs.get());\n\n    public static HystrixDashboardStream getInstance() {\n        return INSTANCE;\n    }\n\n    static HystrixDashboardStream getNonSingletonInstanceOnlyUsedInUnitTests(int delayInMs) {\n        return new HystrixDashboardStream(delayInMs);\n    }\n\n    /**\n     * Return a ref-counted stream that will only do work when at least one subscriber is present\n     */\n    public Observable<DashboardData> observe() {\n        return singleSource;\n    }\n\n    public boolean isSourceCurrentlySubscribed() {\n        return isSourceCurrentlySubscribed.get();\n    }\n\n    public static class DashboardData {\n        final Collection<HystrixCommandMetrics> commandMetrics;\n        final Collection<HystrixThreadPoolMetrics> threadPoolMetrics;\n        final Collection<HystrixCollapserMetrics> collapserMetrics;\n\n        public DashboardData(Collection<HystrixCommandMetrics> commandMetrics, Collection<HystrixThreadPoolMetrics> threadPoolMetrics, Collection<HystrixCollapserMetrics> collapserMetrics) {\n            this.commandMetrics = commandMetrics;\n            this.threadPoolMetrics = threadPoolMetrics;\n            this.collapserMetrics = collapserMetrics;\n        }\n\n        public Collection<HystrixCommandMetrics> getCommandMetrics() {\n            return commandMetrics;\n        }\n\n        public Collection<HystrixThreadPoolMetrics> getThreadPoolMetrics() {\n            return threadPoolMetrics;\n        }\n\n        public Collection<HystrixCollapserMetrics> getCollapserMetrics() {\n            return collapserMetrics;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCollapserBatchSizeDistributionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.metric.HystrixCollapserEvent;\nimport com.netflix.hystrix.metric.HystrixCollapserEventStream;\nimport org.HdrHistogram.Histogram;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of batch size distributions for a given Command.\n * There is a rolling window abstraction on this stream.\n * The latency distribution object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCollapserProperties#metricsRollingPercentileWindowInMilliseconds()}\n * b = {@link HystrixCollapserProperties#metricsRollingPercentileBucketSize()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class, as soon as this stream is queried for the first time.\n */\npublic class RollingCollapserBatchSizeDistributionStream extends RollingDistributionStream<HystrixCollapserEvent> {\n    private static final ConcurrentMap<String, RollingCollapserBatchSizeDistributionStream> streams = new ConcurrentHashMap<String, RollingCollapserBatchSizeDistributionStream>();\n\n    private static final Func2<Histogram, HystrixCollapserEvent, Histogram> addValuesToBucket = new Func2<Histogram, HystrixCollapserEvent, Histogram>() {\n        @Override\n        public Histogram call(Histogram initialDistribution, HystrixCollapserEvent event) {\n            switch (event.getEventType()) {\n                case ADDED_TO_BATCH:\n                    if (event.getCount() > -1) {\n                        initialDistribution.recordValue(event.getCount());\n                    }\n                    break;\n                default:\n                    //do nothing\n                    break;\n            }\n            return initialDistribution;\n        }\n    };\n\n    public static RollingCollapserBatchSizeDistributionStream getInstance(HystrixCollapserKey collapserKey, HystrixCollapserProperties properties) {\n        final int percentileMetricWindow = properties.metricsRollingPercentileWindowInMilliseconds().get();\n        final int numPercentileBuckets = properties.metricsRollingPercentileWindowBuckets().get();\n        final int percentileBucketSizeInMs = percentileMetricWindow / numPercentileBuckets;\n\n        return getInstance(collapserKey, numPercentileBuckets, percentileBucketSizeInMs);\n    }\n\n    public static RollingCollapserBatchSizeDistributionStream getInstance(HystrixCollapserKey collapserKey, int numBuckets, int bucketSizeInMs) {\n        RollingCollapserBatchSizeDistributionStream initialStream = streams.get(collapserKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCollapserBatchSizeDistributionStream.class) {\n                RollingCollapserBatchSizeDistributionStream existingStream = streams.get(collapserKey.name());\n                if (existingStream == null) {\n                    RollingCollapserBatchSizeDistributionStream newStream = new RollingCollapserBatchSizeDistributionStream(collapserKey, numBuckets, bucketSizeInMs);\n                    streams.putIfAbsent(collapserKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCollapserBatchSizeDistributionStream(HystrixCollapserKey collapserKey, int numPercentileBuckets, int percentileBucketSizeInMs) {\n        super(HystrixCollapserEventStream.getInstance(collapserKey), numPercentileBuckets, percentileBucketSizeInMs, addValuesToBucket);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCollapserEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixCollapserEvent;\nimport com.netflix.hystrix.metric.HystrixCollapserEventStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given Command.\n * There is a rolling window abstraction on this stream.\n * The event counters object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link com.netflix.hystrix.HystrixCollapserProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link com.netflix.hystrix.HystrixCollapserProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.  This value (the latest observed value) may be queried using {@link #getLatest(HystrixEventType.Collapser)}.\n */\npublic class RollingCollapserEventCounterStream extends BucketedRollingCounterStream<HystrixCollapserEvent, long[], long[]> {\n\n    private static final ConcurrentMap<String, RollingCollapserEventCounterStream> streams = new ConcurrentHashMap<String, RollingCollapserEventCounterStream>();\n\n    private static final int NUM_EVENT_TYPES = HystrixEventType.Collapser.values().length;\n\n    public static RollingCollapserEventCounterStream getInstance(HystrixCollapserKey collapserKey, HystrixCollapserProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(collapserKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static RollingCollapserEventCounterStream getInstance(HystrixCollapserKey collapserKey, int numBuckets, int bucketSizeInMs) {\n        RollingCollapserEventCounterStream initialStream = streams.get(collapserKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCollapserEventCounterStream.class) {\n                RollingCollapserEventCounterStream existingStream = streams.get(collapserKey.name());\n                if (existingStream == null) {\n                    RollingCollapserEventCounterStream newStream = new RollingCollapserEventCounterStream(collapserKey, numBuckets, bucketSizeInMs, HystrixCollapserMetrics.appendEventToBucket, HystrixCollapserMetrics.bucketAggregator);\n                    streams.putIfAbsent(collapserKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCollapserEventCounterStream(HystrixCollapserKey collapserKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                             Func2<long[], HystrixCollapserEvent, long[]> appendEventToBucket,\n                                             Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixCollapserEventStream.getInstance(collapserKey), numCounterBuckets, counterBucketSizeInMs, appendEventToBucket, reduceBucket);\n    }\n\n    @Override\n    long[] getEmptyBucketSummary() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    @Override\n    long[] getEmptyOutputValue() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    public long getLatest(HystrixEventType.Collapser eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCommandEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given Command.\n * There is a rolling window abstraction on this stream.\n * The event counters object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.  This value (the latest observed value) may be queried using {@link #getLatest(HystrixEventType)}.\n */\npublic class RollingCommandEventCounterStream extends BucketedRollingCounterStream<HystrixCommandCompletion, long[], long[]> {\n\n    private static final ConcurrentMap<String, RollingCommandEventCounterStream> streams = new ConcurrentHashMap<String, RollingCommandEventCounterStream>();\n\n    private static final int NUM_EVENT_TYPES = HystrixEventType.values().length;\n\n    public static RollingCommandEventCounterStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(commandKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static RollingCommandEventCounterStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        RollingCommandEventCounterStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCommandEventCounterStream.class) {\n                RollingCommandEventCounterStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    RollingCommandEventCounterStream newStream = new RollingCommandEventCounterStream(commandKey, numBuckets, bucketSizeInMs,\n                            HystrixCommandMetrics.appendEventToBucket, HystrixCommandMetrics.bucketAggregator);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCommandEventCounterStream(HystrixCommandKey commandKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                             Func2<long[], HystrixCommandCompletion, long[]> reduceCommandCompletion,\n                                             Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixCommandCompletionStream.getInstance(commandKey), numCounterBuckets, counterBucketSizeInMs, reduceCommandCompletion, reduceBucket);\n    }\n\n    @Override\n    long[] getEmptyBucketSummary() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    @Override\n    long[] getEmptyOutputValue() {\n        return new long[NUM_EVENT_TYPES];\n    }\n\n    public long getLatest(HystrixEventType eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCommandLatencyDistributionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport com.netflix.hystrix.metric.HystrixCommandEvent;\nimport org.HdrHistogram.Histogram;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of latency distributions for a given Command.\n * There is a rolling window abstraction on this stream.\n * The latency distribution object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsRollingPercentileWindowInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingPercentileBucketSize()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * The only latencies which get included in the distribution are for those commands which started execution.\n * This relies on {@link HystrixCommandEvent#didCommandExecute()}\n *\n * These values get produced and cached in this class.\n * The distributions can be queried on 2 dimensions:\n * * Execution time or total time\n * ** Execution time is the time spent executing the user-provided execution method.\n * ** Total time is the time spent from the perspecitve of the consumer, and includes all Hystrix bookkeeping.\n */\npublic class RollingCommandLatencyDistributionStream extends RollingDistributionStream<HystrixCommandCompletion> {\n    private static final ConcurrentMap<String, RollingCommandLatencyDistributionStream> streams = new ConcurrentHashMap<String, RollingCommandLatencyDistributionStream>();\n\n    private static final Func2<Histogram, HystrixCommandCompletion, Histogram> addValuesToBucket = new Func2<Histogram, HystrixCommandCompletion, Histogram>() {\n        @Override\n        public Histogram call(Histogram initialDistribution, HystrixCommandCompletion event) {\n            if (event.didCommandExecute() && event.getExecutionLatency() > -1) {\n                initialDistribution.recordValue(event.getExecutionLatency());\n            }\n            return initialDistribution;\n        }\n    };\n\n    public static RollingCommandLatencyDistributionStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int percentileMetricWindow = properties.metricsRollingPercentileWindowInMilliseconds().get();\n        final int numPercentileBuckets = properties.metricsRollingPercentileWindowBuckets().get();\n        final int percentileBucketSizeInMs = percentileMetricWindow / numPercentileBuckets;\n\n        return getInstance(commandKey, numPercentileBuckets, percentileBucketSizeInMs);\n    }\n\n    public static RollingCommandLatencyDistributionStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        RollingCommandLatencyDistributionStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCommandLatencyDistributionStream.class) {\n                RollingCommandLatencyDistributionStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    RollingCommandLatencyDistributionStream newStream = new RollingCommandLatencyDistributionStream(commandKey, numBuckets, bucketSizeInMs);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCommandLatencyDistributionStream(HystrixCommandKey commandKey, int numPercentileBuckets, int percentileBucketSizeInMs) {\n        super(HystrixCommandCompletionStream.getInstance(commandKey), numPercentileBuckets, percentileBucketSizeInMs, addValuesToBucket);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCommandMaxConcurrencyStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.metric.HystrixCommandStartStream;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of the maximum concurrency seen by this command.\n *\n * This gets calculated using a rolling window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new rolling-max is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * This value gets cached in this class.  It may be queried using {@link #getLatestRollingMax()}\n * This value is stable - there's no peeking into a bucket until it is emitted\n *\n */\npublic class RollingCommandMaxConcurrencyStream extends RollingConcurrencyStream {\n\n    private static final ConcurrentMap<String, RollingCommandMaxConcurrencyStream> streams = new ConcurrentHashMap<String, RollingCommandMaxConcurrencyStream>();\n\n    public static RollingCommandMaxConcurrencyStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(commandKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static RollingCommandMaxConcurrencyStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        RollingCommandMaxConcurrencyStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCommandMaxConcurrencyStream.class) {\n                RollingCommandMaxConcurrencyStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    RollingCommandMaxConcurrencyStream newStream = new RollingCommandMaxConcurrencyStream(commandKey, numBuckets, bucketSizeInMs);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCommandMaxConcurrencyStream(final HystrixCommandKey commandKey, final int numBuckets, final int bucketSizeInMs) {\n        super(HystrixCommandStartStream.getInstance(commandKey), numBuckets, bucketSizeInMs);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingCommandUserLatencyDistributionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserProperties;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixCommandCompletionStream;\nimport com.netflix.hystrix.metric.HystrixCommandEvent;\nimport org.HdrHistogram.Histogram;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of latency distributions for a given Command.\n * There is a rolling window abstraction on this stream.\n * The latency distribution object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCollapserProperties#metricsRollingPercentileWindowInMilliseconds()}\n * b = {@link HystrixCollapserProperties#metricsRollingPercentileBucketSize()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * The only latencies which get included in the distribution are for those commands which started execution.\n * This relies on {@link HystrixCommandEvent#didCommandExecute()}\n *\n * These values get produced and cached in this class.\n * The distributions can be queried on 2 dimensions:\n * * Execution time or total time\n * ** Execution time is the time spent executing the user-provided execution method.\n * ** Total time is the time spent from the perspecitve of the consumer, and includes all Hystrix bookkeeping.\n */\npublic class RollingCommandUserLatencyDistributionStream extends RollingDistributionStream<HystrixCommandCompletion> {\n    private static final ConcurrentMap<String, RollingCommandUserLatencyDistributionStream> streams = new ConcurrentHashMap<String, RollingCommandUserLatencyDistributionStream>();\n\n    private static final Func2<Histogram, HystrixCommandCompletion, Histogram> addValuesToBucket = new Func2<Histogram, HystrixCommandCompletion, Histogram>() {\n        @Override\n        public Histogram call(Histogram initialDistribution, HystrixCommandCompletion event) {\n            if (event.didCommandExecute() && event.getTotalLatency() > -1) {\n                initialDistribution.recordValue(event.getTotalLatency());\n            }\n            return initialDistribution;\n        }\n    };\n\n    public static RollingCommandUserLatencyDistributionStream getInstance(HystrixCommandKey commandKey, HystrixCommandProperties properties) {\n        final int percentileMetricWindow = properties.metricsRollingPercentileWindowInMilliseconds().get();\n        final int numPercentileBuckets = properties.metricsRollingPercentileWindowBuckets().get();\n        final int percentileBucketSizeInMs = percentileMetricWindow / numPercentileBuckets;\n\n        return getInstance(commandKey, numPercentileBuckets, percentileBucketSizeInMs);\n    }\n\n    public static RollingCommandUserLatencyDistributionStream getInstance(HystrixCommandKey commandKey, int numBuckets, int bucketSizeInMs) {\n        RollingCommandUserLatencyDistributionStream initialStream = streams.get(commandKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingCommandUserLatencyDistributionStream.class) {\n                RollingCommandUserLatencyDistributionStream existingStream = streams.get(commandKey.name());\n                if (existingStream == null) {\n                    RollingCommandUserLatencyDistributionStream newStream = new RollingCommandUserLatencyDistributionStream(commandKey, numBuckets, bucketSizeInMs);\n                    streams.putIfAbsent(commandKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingCommandUserLatencyDistributionStream(HystrixCommandKey commandKey, int numPercentileBuckets, int percentileBucketSizeInMs) {\n        super(HystrixCommandCompletionStream.getInstance(commandKey), numPercentileBuckets, percentileBucketSizeInMs, addValuesToBucket);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingConcurrencyStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.metric.HystrixCommandExecutionStarted;\nimport com.netflix.hystrix.metric.HystrixEventStream;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.subjects.BehaviorSubject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Maintains a stream of max-concurrency\n *\n * This gets calculated using a rolling window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new rolling-max is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixCommandProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixCommandProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * This value gets cached in this class.  It may be queried using {@link #getLatestRollingMax()}\n *\n * This is a stable value - there's no peeking into a bucket until it is emitted\n */\npublic abstract class RollingConcurrencyStream {\n    private AtomicReference<Subscription> rollingMaxSubscription = new AtomicReference<Subscription>(null);\n    private final BehaviorSubject<Integer> rollingMax = BehaviorSubject.create(0);\n    private final Observable<Integer> rollingMaxStream;\n\n    private static final Func2<Integer, Integer, Integer> reduceToMax = new Func2<Integer, Integer, Integer>() {\n        @Override\n        public Integer call(Integer a, Integer b) {\n            return Math.max(a, b);\n        }\n    };\n\n    private static final Func1<Observable<Integer>, Observable<Integer>> reduceStreamToMax = new Func1<Observable<Integer>, Observable<Integer>>() {\n        @Override\n        public Observable<Integer> call(Observable<Integer> observedConcurrency) {\n            return observedConcurrency.reduce(0, reduceToMax);\n        }\n    };\n\n    private static final Func1<HystrixCommandExecutionStarted, Integer> getConcurrencyCountFromEvent = new Func1<HystrixCommandExecutionStarted, Integer>() {\n        @Override\n        public Integer call(HystrixCommandExecutionStarted event) {\n            return event.getCurrentConcurrency();\n        }\n    };\n\n    protected RollingConcurrencyStream(final HystrixEventStream<HystrixCommandExecutionStarted> inputEventStream, final int numBuckets, final int bucketSizeInMs) {\n        final List<Integer> emptyRollingMaxBuckets = new ArrayList<Integer>();\n        for (int i = 0; i < numBuckets; i++) {\n            emptyRollingMaxBuckets.add(0);\n        }\n\n        rollingMaxStream = inputEventStream\n                .observe()\n                .map(getConcurrencyCountFromEvent)\n                .window(bucketSizeInMs, TimeUnit.MILLISECONDS)\n                .flatMap(reduceStreamToMax)\n                .startWith(emptyRollingMaxBuckets)\n                .window(numBuckets, 1)\n                .flatMap(reduceStreamToMax)\n                .share()\n                .onBackpressureDrop();\n    }\n\n    public void startCachingStreamValuesIfUnstarted() {\n        if (rollingMaxSubscription.get() == null) {\n            //the stream is not yet started\n            Subscription candidateSubscription = observe().subscribe(rollingMax);\n            if (rollingMaxSubscription.compareAndSet(null, candidateSubscription)) {\n                //won the race to set the subscription\n            } else {\n                //lost the race to set the subscription, so we need to cancel this one\n                candidateSubscription.unsubscribe();\n            }\n        }\n    }\n\n    public long getLatestRollingMax() {\n        startCachingStreamValuesIfUnstarted();\n        if (rollingMax.hasValue()) {\n            return rollingMax.getValue();\n        } else {\n            return 0L;\n        }\n    }\n\n    public Observable<Integer> observe() {\n        return rollingMaxStream;\n    }\n\n    public void unsubscribe() {\n        Subscription s = rollingMaxSubscription.get();\n        if (s != null) {\n            s.unsubscribe();\n            rollingMaxSubscription.compareAndSet(s, null);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingDistributionStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.metric.CachedValuesHistogram;\nimport com.netflix.hystrix.metric.HystrixEvent;\nimport com.netflix.hystrix.metric.HystrixEventStream;\nimport org.HdrHistogram.Histogram;\nimport rx.Observable;\nimport rx.Subscription;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.subjects.BehaviorSubject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Maintains a stream of distributions for a given Command.\n * There is a rolling window abstraction on this stream.\n * The latency distribution object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = metricsRollingPercentileWindowInMilliseconds()\n * b = metricsRollingPercentileBucketSize()\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.\n */\npublic class RollingDistributionStream<Event extends HystrixEvent> {\n    private AtomicReference<Subscription> rollingDistributionSubscription = new AtomicReference<Subscription>(null);\n    private final BehaviorSubject<CachedValuesHistogram> rollingDistribution = BehaviorSubject.create(CachedValuesHistogram.backedBy(CachedValuesHistogram.getNewHistogram()));\n    private final Observable<CachedValuesHistogram> rollingDistributionStream;\n\n    private static final Func2<Histogram, Histogram, Histogram> distributionAggregator = new Func2<Histogram, Histogram, Histogram>() {\n        @Override\n        public Histogram call(Histogram initialDistribution, Histogram distributionToAdd) {\n            initialDistribution.add(distributionToAdd);\n            return initialDistribution;\n        }\n    };\n\n    private static final Func1<Observable<Histogram>, Observable<Histogram>> reduceWindowToSingleDistribution = new Func1<Observable<Histogram>, Observable<Histogram>>() {\n        @Override\n        public Observable<Histogram> call(Observable<Histogram> window) {\n            return window.reduce(distributionAggregator);\n        }\n    };\n\n    private static final Func1<Histogram, CachedValuesHistogram> cacheHistogramValues = new Func1<Histogram, CachedValuesHistogram>() {\n        @Override\n        public CachedValuesHistogram call(Histogram histogram) {\n            return CachedValuesHistogram.backedBy(histogram);\n        }\n    };\n\n    private static final Func1<Observable<CachedValuesHistogram>, Observable<List<CachedValuesHistogram>>> convertToList =\n            new Func1<Observable<CachedValuesHistogram>, Observable<List<CachedValuesHistogram>>>() {\n                @Override\n                public Observable<List<CachedValuesHistogram>> call(Observable<CachedValuesHistogram> windowOf2) {\n                    return windowOf2.toList();\n                }\n            };\n\n    protected RollingDistributionStream(final HystrixEventStream<Event> stream, final int numBuckets, final int bucketSizeInMs,\n                                        final Func2<Histogram, Event, Histogram> addValuesToBucket) {\n        final List<Histogram> emptyDistributionsToStart = new ArrayList<Histogram>();\n        for (int i = 0; i < numBuckets; i++) {\n            emptyDistributionsToStart.add(CachedValuesHistogram.getNewHistogram());\n        }\n\n        final Func1<Observable<Event>, Observable<Histogram>> reduceBucketToSingleDistribution = new Func1<Observable<Event>, Observable<Histogram>>() {\n            @Override\n            public Observable<Histogram> call(Observable<Event> bucket) {\n                return bucket.reduce(CachedValuesHistogram.getNewHistogram(), addValuesToBucket);\n            }\n        };\n\n        rollingDistributionStream = stream\n                .observe()\n                .window(bucketSizeInMs, TimeUnit.MILLISECONDS) //stream of unaggregated buckets\n                .flatMap(reduceBucketToSingleDistribution)     //stream of aggregated Histograms\n                .startWith(emptyDistributionsToStart)          //stream of aggregated Histograms that starts with n empty\n                .window(numBuckets, 1)                         //windowed stream: each OnNext is a stream of n Histograms\n                .flatMap(reduceWindowToSingleDistribution)     //reduced stream: each OnNext is a single Histogram\n                .map(cacheHistogramValues)                     //convert to CachedValueHistogram (commonly-accessed values are cached)\n                .share()\n                .onBackpressureDrop();\n    }\n\n    public Observable<CachedValuesHistogram> observe() {\n        return rollingDistributionStream;\n    }\n\n    public int getLatestMean() {\n        CachedValuesHistogram latest = getLatest();\n        if (latest != null) {\n            return latest.getMean();\n        } else {\n            return 0;\n        }\n    }\n\n    public int getLatestPercentile(double percentile) {\n        CachedValuesHistogram latest = getLatest();\n        if (latest != null) {\n            return latest.getValueAtPercentile(percentile);\n        } else {\n            return 0;\n        }\n    }\n\n    public void startCachingStreamValuesIfUnstarted() {\n        if (rollingDistributionSubscription.get() == null) {\n            //the stream is not yet started\n            Subscription candidateSubscription = observe().subscribe(rollingDistribution);\n            if (rollingDistributionSubscription.compareAndSet(null, candidateSubscription)) {\n                //won the race to set the subscription\n            } else {\n                //lost the race to set the subscription, so we need to cancel this one\n                candidateSubscription.unsubscribe();\n            }\n        }\n    }\n\n    CachedValuesHistogram getLatest() {\n        startCachingStreamValuesIfUnstarted();\n        if (rollingDistribution.hasValue()) {\n            return rollingDistribution.getValue();\n        } else {\n            return null;\n        }\n    }\n\n    public void unsubscribe() {\n        Subscription s = rollingDistributionSubscription.get();\n        if (s != null) {\n            s.unsubscribe();\n            rollingDistributionSubscription.compareAndSet(s, null);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingThreadPoolEventCounterStream.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.metric.HystrixCommandCompletion;\nimport com.netflix.hystrix.metric.HystrixThreadPoolCompletionStream;\nimport rx.functions.Func2;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of event counters for a given ThreadPool.\n * There is a rolling window abstraction on this stream.\n * The event counters object is calculated over a window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new set of counters is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * These values are stable - there's no peeking into a bucket until it is emitted\n *\n * These values get produced and cached in this class.\n * You may query to find the latest rolling count of 2 events (executed/rejected) via {@link #getLatestCount(com.netflix.hystrix.HystrixEventType.ThreadPool)}.\n */\npublic class RollingThreadPoolEventCounterStream extends BucketedRollingCounterStream<HystrixCommandCompletion, long[], long[]> {\n\n    private static final ConcurrentMap<String, RollingThreadPoolEventCounterStream> streams = new ConcurrentHashMap<String, RollingThreadPoolEventCounterStream>();\n\n    private static final int ALL_EVENT_TYPES_SIZE = HystrixEventType.ThreadPool.values().length;\n\n    public static RollingThreadPoolEventCounterStream getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(threadPoolKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static RollingThreadPoolEventCounterStream getInstance(HystrixThreadPoolKey threadPoolKey, int numBuckets, int bucketSizeInMs) {\n        RollingThreadPoolEventCounterStream initialStream = streams.get(threadPoolKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingThreadPoolEventCounterStream.class) {\n                RollingThreadPoolEventCounterStream existingStream = streams.get(threadPoolKey.name());\n                if (existingStream == null) {\n                    RollingThreadPoolEventCounterStream newStream =\n                            new RollingThreadPoolEventCounterStream(threadPoolKey, numBuckets, bucketSizeInMs,\n                                    HystrixThreadPoolMetrics.appendEventToBucket, HystrixThreadPoolMetrics.counterAggregator);\n                    streams.putIfAbsent(threadPoolKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    private RollingThreadPoolEventCounterStream(HystrixThreadPoolKey threadPoolKey, int numCounterBuckets, int counterBucketSizeInMs,\n                                                Func2<long[], HystrixCommandCompletion, long[]> reduceCommandCompletion,\n                                                Func2<long[], long[], long[]> reduceBucket) {\n        super(HystrixThreadPoolCompletionStream.getInstance(threadPoolKey), numCounterBuckets, counterBucketSizeInMs, reduceCommandCompletion, reduceBucket);\n    }\n\n    @Override\n    public long[] getEmptyBucketSummary() {\n        return new long[ALL_EVENT_TYPES_SIZE];\n    }\n\n    @Override\n    public long[] getEmptyOutputValue() {\n        return new long[ALL_EVENT_TYPES_SIZE];\n    }\n\n    public long getLatestCount(HystrixEventType.ThreadPool eventType) {\n        return getLatest()[eventType.ordinal()];\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/consumer/RollingThreadPoolMaxConcurrencyStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.metric.HystrixThreadPoolStartStream;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Maintains a stream of max-concurrency\n *\n * This gets calculated using a rolling window of t1 milliseconds.  This window has b buckets.\n * Therefore, a new rolling-max is produced every t2 (=t1/b) milliseconds\n * t1 = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}\n * b = {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowBuckets()}\n *\n * This value gets cached in this class.  It may be queried using {@link #getLatestRollingMax()}\n *\n * This is a stable value - there's no peeking into a bucket until it is emitted\n */\npublic class RollingThreadPoolMaxConcurrencyStream extends RollingConcurrencyStream {\n\n    private static final ConcurrentMap<String, RollingThreadPoolMaxConcurrencyStream> streams = new ConcurrentHashMap<String, RollingThreadPoolMaxConcurrencyStream>();\n\n    public static RollingThreadPoolMaxConcurrencyStream getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties properties) {\n        final int counterMetricWindow = properties.metricsRollingStatisticalWindowInMilliseconds().get();\n        final int numCounterBuckets = properties.metricsRollingStatisticalWindowBuckets().get();\n        final int counterBucketSizeInMs = counterMetricWindow / numCounterBuckets;\n\n        return getInstance(threadPoolKey, numCounterBuckets, counterBucketSizeInMs);\n    }\n\n    public static RollingThreadPoolMaxConcurrencyStream getInstance(HystrixThreadPoolKey threadPoolKey, int numBuckets, int bucketSizeInMs) {\n        RollingThreadPoolMaxConcurrencyStream initialStream = streams.get(threadPoolKey.name());\n        if (initialStream != null) {\n            return initialStream;\n        } else {\n            synchronized (RollingThreadPoolMaxConcurrencyStream.class) {\n                RollingThreadPoolMaxConcurrencyStream existingStream = streams.get(threadPoolKey.name());\n                if (existingStream == null) {\n                    RollingThreadPoolMaxConcurrencyStream newStream =\n                            new RollingThreadPoolMaxConcurrencyStream(threadPoolKey, numBuckets, bucketSizeInMs);\n                    streams.putIfAbsent(threadPoolKey.name(), newStream);\n                    return newStream;\n                } else {\n                    return existingStream;\n                }\n            }\n        }\n    }\n\n    public static void reset() {\n        streams.clear();\n    }\n\n    public RollingThreadPoolMaxConcurrencyStream(final HystrixThreadPoolKey threadPoolKey, final int numBuckets, final int bucketSizeInMs) {\n        super(HystrixThreadPoolStartStream.getInstance(threadPoolKey), numBuckets, bucketSizeInMs);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/sample/HystrixCommandUtilization.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.sample;\n\nimport com.netflix.hystrix.HystrixCommandMetrics;\n\npublic class HystrixCommandUtilization {\n    private final int concurrentCommandCount;\n\n    public HystrixCommandUtilization(int concurrentCommandCount) {\n        this.concurrentCommandCount = concurrentCommandCount;\n    }\n\n    public static HystrixCommandUtilization sample(HystrixCommandMetrics commandMetrics) {\n        return new HystrixCommandUtilization(commandMetrics.getCurrentConcurrentExecutionCount());\n    }\n\n    public int getConcurrentCommandCount() {\n        return concurrentCommandCount;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/sample/HystrixThreadPoolUtilization.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.sample;\n\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\n\npublic class HystrixThreadPoolUtilization {\n    private final int currentActiveCount;\n    private final int currentCorePoolSize;\n    private final int currentPoolSize;\n    private final int currentQueueSize;\n\n    public HystrixThreadPoolUtilization(int currentActiveCount, int currentCorePoolSize, int currentPoolSize, int currentQueueSize) {\n        this.currentActiveCount = currentActiveCount;\n        this.currentCorePoolSize = currentCorePoolSize;\n        this.currentPoolSize = currentPoolSize;\n        this.currentQueueSize = currentQueueSize;\n    }\n\n    public static HystrixThreadPoolUtilization sample(HystrixThreadPoolMetrics threadPoolMetrics) {\n        return new HystrixThreadPoolUtilization(\n                threadPoolMetrics.getCurrentActiveCount().intValue(),\n                threadPoolMetrics.getCurrentCorePoolSize().intValue(),\n                threadPoolMetrics.getCurrentPoolSize().intValue(),\n                threadPoolMetrics.getCurrentQueueSize().intValue()\n        );\n    }\n\n    public int getCurrentActiveCount() {\n        return currentActiveCount;\n    }\n\n    public int getCurrentCorePoolSize() {\n        return currentCorePoolSize;\n    }\n\n    public int getCurrentPoolSize() {\n        return currentPoolSize;\n    }\n\n    public int getCurrentQueueSize() {\n        return currentQueueSize;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/sample/HystrixUtilization.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.sample;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\n\nimport java.util.Map;\n\npublic class HystrixUtilization {\n    private final Map<HystrixCommandKey, HystrixCommandUtilization> commandUtilizationMap;\n    private final Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> threadPoolUtilizationMap;\n\n    public HystrixUtilization(Map<HystrixCommandKey, HystrixCommandUtilization> commandUtilizationMap, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> threadPoolUtilizationMap) {\n        this.commandUtilizationMap = commandUtilizationMap;\n        this.threadPoolUtilizationMap = threadPoolUtilizationMap;\n    }\n\n    public static HystrixUtilization from(Map<HystrixCommandKey, HystrixCommandUtilization> commandUtilizationMap,\n            Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> threadPoolUtilizationMap) {\n        return new HystrixUtilization(commandUtilizationMap, threadPoolUtilizationMap);\n    }\n\n    public Map<HystrixCommandKey, HystrixCommandUtilization> getCommandUtilizationMap() {\n        return commandUtilizationMap;\n    }\n\n    public Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> getThreadPoolUtilizationMap() {\n        return threadPoolUtilizationMap;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/metric/sample/HystrixUtilizationStream.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.sample;\n\nimport com.netflix.config.DynamicIntProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport rx.Observable;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * This class samples current Hystrix utilization of resources and exposes that as a stream\n */\npublic class HystrixUtilizationStream {\n    private final int intervalInMilliseconds;\n    private final Observable<HystrixUtilization> allUtilizationStream;\n    private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);\n\n    private static final DynamicIntProperty dataEmissionIntervalInMs =\n            DynamicPropertyFactory.getInstance().getIntProperty(\"hystrix.stream.utilization.intervalInMilliseconds\", 500);\n\n\n    private static final Func1<Long, HystrixUtilization> getAllUtilization =\n            new Func1<Long, HystrixUtilization>() {\n                @Override\n                public HystrixUtilization call(Long timestamp) {\n                    return HystrixUtilization.from(\n                            getAllCommandUtilization.call(timestamp),\n                            getAllThreadPoolUtilization.call(timestamp)\n                    );\n                }\n            };\n\n    /**\n     * @deprecated Not for public use.  Please use {@link #getInstance()}.  This facilitates better stream-sharing\n     * @param intervalInMilliseconds milliseconds between data emissions\n     */\n    @Deprecated //deprecated in 1.5.4.\n    public HystrixUtilizationStream(final int intervalInMilliseconds) {\n        this.intervalInMilliseconds = intervalInMilliseconds;\n        this.allUtilizationStream = Observable.interval(intervalInMilliseconds, TimeUnit.MILLISECONDS)\n                .map(getAllUtilization)\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(true);\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        isSourceCurrentlySubscribed.set(false);\n                    }\n                })\n                .share()\n                .onBackpressureDrop();\n    }\n\n    //The data emission interval is looked up on startup only\n    private static final HystrixUtilizationStream INSTANCE =\n            new HystrixUtilizationStream(dataEmissionIntervalInMs.get());\n\n    public static HystrixUtilizationStream getInstance() {\n        return INSTANCE;\n    }\n\n    static HystrixUtilizationStream getNonSingletonInstanceOnlyUsedInUnitTests(int delayInMs) {\n        return new HystrixUtilizationStream(delayInMs);\n    }\n\n    /**\n     * Return a ref-counted stream that will only do work when at least one subscriber is present\n     */\n    public Observable<HystrixUtilization> observe() {\n        return allUtilizationStream;\n    }\n\n    public Observable<Map<HystrixCommandKey, HystrixCommandUtilization>> observeCommandUtilization() {\n        return allUtilizationStream.map(getOnlyCommandUtilization);\n    }\n\n    public Observable<Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> observeThreadPoolUtilization() {\n        return allUtilizationStream.map(getOnlyThreadPoolUtilization);\n    }\n\n    public int getIntervalInMilliseconds() {\n        return this.intervalInMilliseconds;\n    }\n\n    public boolean isSourceCurrentlySubscribed() {\n        return isSourceCurrentlySubscribed.get();\n    }\n\n    private static HystrixCommandUtilization sampleCommandUtilization(HystrixCommandMetrics commandMetrics) {\n        return HystrixCommandUtilization.sample(commandMetrics);\n    }\n\n    private static HystrixThreadPoolUtilization sampleThreadPoolUtilization(HystrixThreadPoolMetrics threadPoolMetrics) {\n        return HystrixThreadPoolUtilization.sample(threadPoolMetrics);\n    }\n\n    private static final Func1<Long, Map<HystrixCommandKey, HystrixCommandUtilization>> getAllCommandUtilization =\n            new Func1<Long, Map<HystrixCommandKey, HystrixCommandUtilization>>() {\n                @Override\n                public Map<HystrixCommandKey, HystrixCommandUtilization> call(Long timestamp) {\n                    Map<HystrixCommandKey, HystrixCommandUtilization> commandUtilizationPerKey = new HashMap<HystrixCommandKey, HystrixCommandUtilization>();\n                    for (HystrixCommandMetrics commandMetrics: HystrixCommandMetrics.getInstances()) {\n                        HystrixCommandKey commandKey = commandMetrics.getCommandKey();\n                        commandUtilizationPerKey.put(commandKey, sampleCommandUtilization(commandMetrics));\n                    }\n                    return commandUtilizationPerKey;\n                }\n            };\n\n    private static final Func1<Long, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> getAllThreadPoolUtilization =\n            new Func1<Long, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>>() {\n                @Override\n                public Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> call(Long timestamp) {\n                    Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> threadPoolUtilizationPerKey = new HashMap<HystrixThreadPoolKey, HystrixThreadPoolUtilization>();\n                    for (HystrixThreadPoolMetrics threadPoolMetrics: HystrixThreadPoolMetrics.getInstances()) {\n                        HystrixThreadPoolKey threadPoolKey = threadPoolMetrics.getThreadPoolKey();\n                        threadPoolUtilizationPerKey.put(threadPoolKey, sampleThreadPoolUtilization(threadPoolMetrics));\n                    }\n                    return threadPoolUtilizationPerKey;\n                }\n            };\n\n    private static final Func1<HystrixUtilization, Map<HystrixCommandKey, HystrixCommandUtilization>> getOnlyCommandUtilization =\n            new Func1<HystrixUtilization, Map<HystrixCommandKey, HystrixCommandUtilization>>() {\n                @Override\n                public Map<HystrixCommandKey, HystrixCommandUtilization> call(HystrixUtilization hystrixUtilization) {\n                    return hystrixUtilization.getCommandUtilizationMap();\n                }\n            };\n\n    private static final Func1<HystrixUtilization, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> getOnlyThreadPoolUtilization =\n            new Func1<HystrixUtilization, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>>() {\n                @Override\n                public Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> call(HystrixUtilization hystrixUtilization) {\n                    return hystrixUtilization.getThreadPoolUtilizationMap();\n                }\n            };\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Core functionality of Hystrix including the HystrixCommand and HystrixCollapser to be extended from.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixArchaiusHelper.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperties;\n\n/**\n * @ExcludeFromJavadoc\n * @author agentgt\n */\nclass HystrixArchaiusHelper {\n\n    /**\n     * To keep class loading minimal for those that have archaius in the classpath but choose not to use it.\n     * @ExcludeFromJavadoc\n     * @author agent\n     */\n    private static class LazyHolder {\n        private final static Method loadCascadedPropertiesFromResources;\n        private final static String CONFIG_MANAGER_CLASS = \"com.netflix.config.ConfigurationManager\";\n    \n        static {\n            Method load = null;\n            try {\n                Class<?> configManager = Class.forName(CONFIG_MANAGER_CLASS);\n                load = configManager.getMethod(\"loadCascadedPropertiesFromResources\", String.class);\n            } catch (Exception e) {\n            }\n    \n            loadCascadedPropertiesFromResources = load;\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    static boolean isArchaiusV1Available() {\n        return LazyHolder.loadCascadedPropertiesFromResources != null;\n    }\n\n    static void loadCascadedPropertiesFromResources(String name) {\n        if (isArchaiusV1Available()) {\n            try {\n                LazyHolder.loadCascadedPropertiesFromResources.invoke(null, name);\n            } catch (IllegalAccessException e) {\n            } catch (IllegalArgumentException e) {\n            } catch (InvocationTargetException e) {\n            }\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    static HystrixDynamicProperties createArchaiusDynamicProperties() {\n        if (isArchaiusV1Available()) {\n            loadCascadedPropertiesFromResources(\"hystrix-plugins\");\n            try {\n                Class<?> defaultProperties = Class.forName(\n                        \"com.netflix.hystrix.strategy.properties.archaius\" + \".HystrixDynamicPropertiesArchaius\");\n                return (HystrixDynamicProperties) defaultProperties.newInstance();\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e);\n            } catch (InstantiationException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        // Fallback to System properties.\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy;\n\nimport java.util.ServiceConfigurationError;\nimport java.util.ServiceLoader;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifierDefault;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHookDefault;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherDefault;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperties;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesSystemProperties;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategyDefault;\n\n/**\n * Registry for plugin implementations that allows global override and handles the retrieval of correct implementation based on order of precedence:\n * <ol>\n * <li>plugin registered globally via <code>register</code> methods in this class</li>\n * <li>plugin registered and retrieved using the resolved {@link HystrixDynamicProperties} (usually Archaius, see get methods for property names)</li>\n * <li>plugin registered and retrieved using the JDK {@link ServiceLoader}</li>\n * <li>default implementation</li>\n * </ol>\n * \n * The exception to the above order is the {@link HystrixDynamicProperties} implementation \n * which is only loaded through <code>System.properties</code> or the ServiceLoader (see the {@link HystrixPlugins#getDynamicProperties() getter} for more details).\n * <p>\n * See the Hystrix GitHub Wiki for more information: <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n */\npublic class HystrixPlugins {\n    \n    //We should not load unless we are requested to. This avoids accidental initialization. @agentgt\n    //See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom\n    private static class LazyHolder { private static final HystrixPlugins INSTANCE = HystrixPlugins.create(); }\n    private final ClassLoader classLoader;\n    /* package */ final AtomicReference<HystrixEventNotifier> notifier = new AtomicReference<HystrixEventNotifier>();\n    /* package */ final AtomicReference<HystrixConcurrencyStrategy> concurrencyStrategy = new AtomicReference<HystrixConcurrencyStrategy>();\n    /* package */ final AtomicReference<HystrixMetricsPublisher> metricsPublisher = new AtomicReference<HystrixMetricsPublisher>();\n    /* package */ final AtomicReference<HystrixPropertiesStrategy> propertiesFactory = new AtomicReference<HystrixPropertiesStrategy>();\n    /* package */ final AtomicReference<HystrixCommandExecutionHook> commandExecutionHook = new AtomicReference<HystrixCommandExecutionHook>();\n    private final HystrixDynamicProperties dynamicProperties;\n\n    \n    private HystrixPlugins(ClassLoader classLoader, LoggerSupplier logSupplier) {\n        //This will load Archaius if its in the classpath.\n        this.classLoader = classLoader;\n        //N.B. Do not use a logger before this is loaded as it will most likely load the configuration system.\n        //The configuration system may need to do something prior to loading logging. @agentgt\n        dynamicProperties = resolveDynamicProperties(classLoader, logSupplier);\n    }\n\n    /**\n     * For unit test purposes.\n     * @ExcludeFromJavadoc\n     */\n    /* private */ static HystrixPlugins create(ClassLoader classLoader, LoggerSupplier logSupplier) {\n        return new HystrixPlugins(classLoader, logSupplier);\n    }\n    \n    /**\n     * For unit test purposes.\n     * @ExcludeFromJavadoc\n     */\n    /* private */ static HystrixPlugins create(ClassLoader classLoader) {\n        return new HystrixPlugins(classLoader, new LoggerSupplier() {\n            @Override\n            public Logger getLogger() {\n                return LoggerFactory.getLogger(HystrixPlugins.class);\n            }\n        });\n    }\n    /**\n     * @ExcludeFromJavadoc\n     */\n    /* private */ static HystrixPlugins create() {\n        return create(HystrixPlugins.class.getClassLoader());\n    }\n\n    public static HystrixPlugins getInstance() {\n        return LazyHolder.INSTANCE;\n    }\n\n    /**\n     * Reset all of the HystrixPlugins to null.  You may invoke this directly, or it also gets invoked via <code>Hystrix.reset()</code>\n     */\n    public static void reset() {\n        getInstance().notifier.set(null);\n        getInstance().concurrencyStrategy.set(null);\n        getInstance().metricsPublisher.set(null);\n        getInstance().propertiesFactory.set(null);\n        getInstance().commandExecutionHook.set(null);\n        HystrixMetricsPublisherFactory.reset();\n    }\n\n    /**\n     * Retrieve instance of {@link HystrixEventNotifier} to use based on order of precedence as defined in {@link HystrixPlugins} class header.\n     * <p>\n     * Override default by using {@link #registerEventNotifier(HystrixEventNotifier)} or setting property (via Archaius): <code>hystrix.plugin.HystrixEventNotifier.implementation</code> with the full classname to\n     * load.\n     * \n     * @return {@link HystrixEventNotifier} implementation to use\n     */\n    public HystrixEventNotifier getEventNotifier() {\n        if (notifier.get() == null) {\n            // check for an implementation from Archaius first\n            Object impl = getPluginImplementation(HystrixEventNotifier.class);\n            if (impl == null) {\n                // nothing set via Archaius so initialize with default\n                notifier.compareAndSet(null, HystrixEventNotifierDefault.getInstance());\n                // we don't return from here but call get() again in case of thread-race so the winner will always get returned\n            } else {\n                // we received an implementation from Archaius so use it\n                notifier.compareAndSet(null, (HystrixEventNotifier) impl);\n            }\n        }\n        return notifier.get();\n    }\n\n    /**\n     * Register a {@link HystrixEventNotifier} implementation as a global override of any injected or default implementations.\n     * \n     * @param impl\n     *            {@link HystrixEventNotifier} implementation\n     * @throws IllegalStateException\n     *             if called more than once or after the default was initialized (if usage occurs before trying to register)\n     */\n    public void registerEventNotifier(HystrixEventNotifier impl) {\n        if (!notifier.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\"Another strategy was already registered.\");\n        }\n    }\n\n    /**\n     * Retrieve instance of {@link HystrixConcurrencyStrategy} to use based on order of precedence as defined in {@link HystrixPlugins} class header.\n     * <p>\n     * Override default by using {@link #registerConcurrencyStrategy(HystrixConcurrencyStrategy)} or setting property (via Archaius): <code>hystrix.plugin.HystrixConcurrencyStrategy.implementation</code> with the\n     * full classname to load.\n     * \n     * @return {@link HystrixConcurrencyStrategy} implementation to use\n     */\n    public HystrixConcurrencyStrategy getConcurrencyStrategy() {\n        if (concurrencyStrategy.get() == null) {\n            // check for an implementation from Archaius first\n            Object impl = getPluginImplementation(HystrixConcurrencyStrategy.class);\n            if (impl == null) {\n                // nothing set via Archaius so initialize with default\n                concurrencyStrategy.compareAndSet(null, HystrixConcurrencyStrategyDefault.getInstance());\n                // we don't return from here but call get() again in case of thread-race so the winner will always get returned\n            } else {\n                // we received an implementation from Archaius so use it\n                concurrencyStrategy.compareAndSet(null, (HystrixConcurrencyStrategy) impl);\n            }\n        }\n        return concurrencyStrategy.get();\n    }\n\n    /**\n     * Register a {@link HystrixConcurrencyStrategy} implementation as a global override of any injected or default implementations.\n     * \n     * @param impl\n     *            {@link HystrixConcurrencyStrategy} implementation\n     * @throws IllegalStateException\n     *             if called more than once or after the default was initialized (if usage occurs before trying to register)\n     */\n    public void registerConcurrencyStrategy(HystrixConcurrencyStrategy impl) {\n        if (!concurrencyStrategy.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\"Another strategy was already registered.\");\n        }\n    }\n\n    /**\n     * Retrieve instance of {@link HystrixMetricsPublisher} to use based on order of precedence as defined in {@link HystrixPlugins} class header.\n     * <p>\n     * Override default by using {@link #registerMetricsPublisher(HystrixMetricsPublisher)} or setting property (via Archaius): <code>hystrix.plugin.HystrixMetricsPublisher.implementation</code> with the full\n     * classname to load.\n     * \n     * @return {@link HystrixMetricsPublisher} implementation to use\n     */\n    public HystrixMetricsPublisher getMetricsPublisher() {\n        if (metricsPublisher.get() == null) {\n            // check for an implementation from Archaius first\n            Object impl = getPluginImplementation(HystrixMetricsPublisher.class);\n            if (impl == null) {\n                // nothing set via Archaius so initialize with default\n                metricsPublisher.compareAndSet(null, HystrixMetricsPublisherDefault.getInstance());\n                // we don't return from here but call get() again in case of thread-race so the winner will always get returned\n            } else {\n                // we received an implementation from Archaius so use it\n                metricsPublisher.compareAndSet(null, (HystrixMetricsPublisher) impl);\n            }\n        }\n        return metricsPublisher.get();\n    }\n\n    /**\n     * Register a {@link HystrixMetricsPublisher} implementation as a global override of any injected or default implementations.\n     * \n     * @param impl\n     *            {@link HystrixMetricsPublisher} implementation\n     * @throws IllegalStateException\n     *             if called more than once or after the default was initialized (if usage occurs before trying to register)\n     */\n    public void registerMetricsPublisher(HystrixMetricsPublisher impl) {\n        if (!metricsPublisher.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\"Another strategy was already registered.\");\n        }\n    }\n\n    /**\n     * Retrieve instance of {@link HystrixPropertiesStrategy} to use based on order of precedence as defined in {@link HystrixPlugins} class header.\n     * <p>\n     * Override default by using {@link #registerPropertiesStrategy(HystrixPropertiesStrategy)} or setting property (via Archaius): <code>hystrix.plugin.HystrixPropertiesStrategy.implementation</code> with the full\n     * classname to load.\n     * \n     * @return {@link HystrixPropertiesStrategy} implementation to use\n     */\n    public HystrixPropertiesStrategy getPropertiesStrategy() {\n        if (propertiesFactory.get() == null) {\n            // check for an implementation from Archaius first\n            Object impl = getPluginImplementation(HystrixPropertiesStrategy.class);\n            if (impl == null) {\n                // nothing set via Archaius so initialize with default\n                propertiesFactory.compareAndSet(null, HystrixPropertiesStrategyDefault.getInstance());\n                // we don't return from here but call get() again in case of thread-race so the winner will always get returned\n            } else {\n                // we received an implementation from Archaius so use it\n                propertiesFactory.compareAndSet(null, (HystrixPropertiesStrategy) impl);\n            }\n        }\n        return propertiesFactory.get();\n    }\n    \n    /**\n     * Retrieves the instance of {@link HystrixDynamicProperties} to use.\n     * <p>\n     * Unlike the other plugins this plugin cannot be re-registered and is only loaded at creation \n     * of the {@link HystrixPlugins} singleton.\n     * <p>\n     * The order of precedence for loading implementations is:\n     * <ol>\n     * <li>System property of key: <code>hystrix.plugin.HystrixDynamicProperties.implementation</code> with the class as a value.</li>\n     * <li>The {@link ServiceLoader}.</li>\n     * <li>An implementation based on Archaius if it is found in the classpath is used.</li>\n     * <li>A fallback implementation based on the {@link System#getProperties()}</li>\n     * </ol>\n     * @return never <code>null</code>\n     */\n    public HystrixDynamicProperties getDynamicProperties() {\n        return dynamicProperties;\n    }\n\n    /**\n     * Register a {@link HystrixPropertiesStrategy} implementation as a global override of any injected or default implementations.\n     * \n     * @param impl\n     *            {@link HystrixPropertiesStrategy} implementation\n     * @throws IllegalStateException\n     *             if called more than once or after the default was initialized (if usage occurs before trying to register)\n     */\n    public void registerPropertiesStrategy(HystrixPropertiesStrategy impl) {\n        if (!propertiesFactory.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\"Another strategy was already registered.\");\n        }\n    }\n\n    /**\n     * Retrieve instance of {@link HystrixCommandExecutionHook} to use based on order of precedence as defined in {@link HystrixPlugins} class header.\n     * <p>\n     * Override default by using {@link #registerCommandExecutionHook(HystrixCommandExecutionHook)} or setting property (via Archaius): <code>hystrix.plugin.HystrixCommandExecutionHook.implementation</code> with the\n     * full classname to\n     * load.\n     * \n     * @return {@link HystrixCommandExecutionHook} implementation to use\n     * \n     * @since 1.2\n     */\n    public HystrixCommandExecutionHook getCommandExecutionHook() {\n        if (commandExecutionHook.get() == null) {\n            // check for an implementation from Archaius first\n            Object impl = getPluginImplementation(HystrixCommandExecutionHook.class);\n            if (impl == null) {\n                // nothing set via Archaius so initialize with default\n                commandExecutionHook.compareAndSet(null, HystrixCommandExecutionHookDefault.getInstance());\n                // we don't return from here but call get() again in case of thread-race so the winner will always get returned\n            } else {\n                // we received an implementation from Archaius so use it\n                commandExecutionHook.compareAndSet(null, (HystrixCommandExecutionHook) impl);\n            }\n        }\n        return commandExecutionHook.get();\n    }\n\n    /**\n     * Register a {@link HystrixCommandExecutionHook} implementation as a global override of any injected or default implementations.\n     * \n     * @param impl\n     *            {@link HystrixCommandExecutionHook} implementation\n     * @throws IllegalStateException\n     *             if called more than once or after the default was initialized (if usage occurs before trying to register)\n     * \n     * @since 1.2\n     */\n    public void registerCommandExecutionHook(HystrixCommandExecutionHook impl) {\n        if (!commandExecutionHook.compareAndSet(null, impl)) {\n            throw new IllegalStateException(\"Another strategy was already registered.\");\n        }\n    }\n\n    \n    private <T> T getPluginImplementation(Class<T> pluginClass) {\n        T p = getPluginImplementationViaProperties(pluginClass, dynamicProperties);\n        if (p != null) return p;        \n        return findService(pluginClass, classLoader);\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private static <T> T getPluginImplementationViaProperties(Class<T> pluginClass, HystrixDynamicProperties dynamicProperties) {\n        String classSimpleName = pluginClass.getSimpleName();\n        // Check Archaius for plugin class.\n        String propertyName = \"hystrix.plugin.\" + classSimpleName + \".implementation\";\n        String implementingClass = dynamicProperties.getString(propertyName, null).get();\n        if (implementingClass != null) {\n            try {\n                Class<?> cls = Class.forName(implementingClass);\n                // narrow the scope (cast) to the type we're expecting\n                cls = cls.asSubclass(pluginClass);\n                return (T) cls.newInstance();\n            } catch (ClassCastException e) {\n                throw new RuntimeException(classSimpleName + \" implementation is not an instance of \" + classSimpleName + \": \" + implementingClass);\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(classSimpleName + \" implementation class not found: \" + implementingClass, e);\n            } catch (InstantiationException e) {\n                throw new RuntimeException(classSimpleName + \" implementation not able to be instantiated: \" + implementingClass, e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(classSimpleName + \" implementation not able to be accessed: \" + implementingClass, e);\n            }\n        } else {\n            return null;\n        }\n    }\n    \n    \n\n    private static HystrixDynamicProperties resolveDynamicProperties(ClassLoader classLoader, LoggerSupplier logSupplier) {\n        HystrixDynamicProperties hp = getPluginImplementationViaProperties(HystrixDynamicProperties.class, \n                HystrixDynamicPropertiesSystemProperties.getInstance());\n        if (hp != null) {\n            logSupplier.getLogger().debug(\n                    \"Created HystrixDynamicProperties instance from System property named \"\n                    + \"\\\"hystrix.plugin.HystrixDynamicProperties.implementation\\\". Using class: {}\", \n                    hp.getClass().getCanonicalName());\n            return hp;\n        }\n        hp = findService(HystrixDynamicProperties.class, classLoader);\n        if (hp != null) {\n            logSupplier.getLogger()\n                    .debug(\"Created HystrixDynamicProperties instance by loading from ServiceLoader. Using class: {}\", \n                            hp.getClass().getCanonicalName());\n            return hp;\n        }\n        hp = HystrixArchaiusHelper.createArchaiusDynamicProperties();\n        if (hp != null) {\n            logSupplier.getLogger().debug(\"Created HystrixDynamicProperties. Using class : {}\", \n                    hp.getClass().getCanonicalName());\n            return hp;\n        }\n        hp = HystrixDynamicPropertiesSystemProperties.getInstance();\n        logSupplier.getLogger().info(\"Using System Properties for HystrixDynamicProperties! Using class: {}\", \n                hp.getClass().getCanonicalName());\n        return hp;\n    }\n    \n    private static <T> T findService(\n            Class<T> spi, \n            ClassLoader classLoader) throws ServiceConfigurationError {\n        \n        ServiceLoader<T> sl = ServiceLoader.load(spi,\n                classLoader);\n        for (T s : sl) {\n            if (s != null)\n                return s;\n        }\n        return null;\n    }\n    \n    interface LoggerSupplier {\n        Logger getLogger();\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixConcurrencyStrategy.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.PlatformSpecific;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Abstract class for defining different behavior or implementations for concurrency related aspects of the system with default implementations.\n * <p>\n * For example, every {@link Callable} executed by {@link HystrixCommand} will call {@link #wrapCallable(Callable)} to give a chance for custom implementations to decorate the {@link Callable} with\n * additional behavior.\n * <p>\n * When you implement a concrete {@link HystrixConcurrencyStrategy}, you should make the strategy idempotent w.r.t ThreadLocals.\n * Since the usage of threads by Hystrix is internal, Hystrix does not attempt to apply the strategy in an idempotent way.\n * Instead, you should write your strategy to work idempotently.  See https://github.com/Netflix/Hystrix/issues/351 for a more detailed discussion.\n * <p>\n * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a\n * href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n */\npublic abstract class HystrixConcurrencyStrategy {\n\n    private final static Logger logger = LoggerFactory.getLogger(HystrixConcurrencyStrategy.class);\n\n    /**\n     * Factory method to provide {@link ThreadPoolExecutor} instances as desired.\n     * <p>\n     * Note that the corePoolSize, maximumPoolSize and keepAliveTime values will be dynamically set during runtime if their values change using the {@link ThreadPoolExecutor#setCorePoolSize},\n     * {@link ThreadPoolExecutor#setMaximumPoolSize} and {@link ThreadPoolExecutor#setKeepAliveTime} methods.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Implementation using standard java.util.concurrent.ThreadPoolExecutor\n     * \n     * @param threadPoolKey\n     *            {@link HystrixThreadPoolKey} representing the {@link HystrixThreadPool} that this {@link ThreadPoolExecutor} will be used for.\n     * @param corePoolSize\n     *            Core number of threads requested via properties (or system default if no properties set).\n     * @param maximumPoolSize\n     *            Max number of threads requested via properties (or system default if no properties set).\n     * @param keepAliveTime\n     *            Keep-alive time for threads requested via properties (or system default if no properties set).\n     * @param unit\n     *            {@link TimeUnit} corresponding with keepAliveTime\n     * @param workQueue\n     *            {@code BlockingQueue<Runnable>} as provided by {@link #getBlockingQueue(int)}\n     * @return instance of {@link ThreadPoolExecutor}\n     */\n    public ThreadPoolExecutor getThreadPool(final HystrixThreadPoolKey threadPoolKey, HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize, HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {\n        final ThreadFactory threadFactory = getThreadFactory(threadPoolKey);\n\n        final int dynamicCoreSize = corePoolSize.get();\n        final int dynamicMaximumSize = maximumPoolSize.get();\n\n        if (dynamicCoreSize > dynamicMaximumSize) {\n            logger.error(\"Hystrix ThreadPool configuration at startup for : \" + threadPoolKey.name() + \" is trying to set coreSize = \" +\n                    dynamicCoreSize + \" and maximumSize = \" + dynamicMaximumSize + \".  Maximum size will be set to \" +\n                    dynamicCoreSize + \", the coreSize value, since it must be equal to or greater than the coreSize value\");\n            return new ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime.get(), unit, workQueue, threadFactory);\n        } else {\n            return new ThreadPoolExecutor(dynamicCoreSize, dynamicMaximumSize, keepAliveTime.get(), unit, workQueue, threadFactory);\n        }\n    }\n\n    public ThreadPoolExecutor getThreadPool(final HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {\n        final ThreadFactory threadFactory = getThreadFactory(threadPoolKey);\n\n        final boolean allowMaximumSizeToDivergeFromCoreSize = threadPoolProperties.getAllowMaximumSizeToDivergeFromCoreSize().get();\n        final int dynamicCoreSize = threadPoolProperties.coreSize().get();\n        final int keepAliveTime = threadPoolProperties.keepAliveTimeMinutes().get();\n        final int maxQueueSize = threadPoolProperties.maxQueueSize().get();\n        final BlockingQueue<Runnable> workQueue = getBlockingQueue(maxQueueSize);\n\n        if (allowMaximumSizeToDivergeFromCoreSize) {\n            final int dynamicMaximumSize = threadPoolProperties.maximumSize().get();\n            if (dynamicCoreSize > dynamicMaximumSize) {\n                logger.error(\"Hystrix ThreadPool configuration at startup for : \" + threadPoolKey.name() + \" is trying to set coreSize = \" +\n                        dynamicCoreSize + \" and maximumSize = \" + dynamicMaximumSize + \".  Maximum size will be set to \" +\n                        dynamicCoreSize + \", the coreSize value, since it must be equal to or greater than the coreSize value\");\n                return new ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);\n            } else {\n                return new ThreadPoolExecutor(dynamicCoreSize, dynamicMaximumSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);\n            }\n        } else {\n            return new ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);\n        }\n    }\n\n    private static ThreadFactory getThreadFactory(final HystrixThreadPoolKey threadPoolKey) {\n        if (!PlatformSpecific.isAppEngineStandardEnvironment()) {\n            return new ThreadFactory() {\n                private final AtomicInteger threadNumber = new AtomicInteger(0);\n\n                @Override\n                public Thread newThread(Runnable r) {\n                    Thread thread = new Thread(r, \"hystrix-\" + threadPoolKey.name() + \"-\" + threadNumber.incrementAndGet());\n                    thread.setDaemon(true);\n                    return thread;\n                }\n\n            };\n        } else {\n            return PlatformSpecific.getAppEngineThreadFactory();\n        }\n    }\n\n    /**\n     * Factory method to provide instance of {@code BlockingQueue<Runnable>} used for each {@link ThreadPoolExecutor} as constructed in {@link #getThreadPool}.\n     * <p>\n     * Note: The maxQueueSize value is provided so any type of queue can be used but typically an implementation such as {@link SynchronousQueue} without a queue (just a handoff) is preferred as\n     * queueing is an anti-pattern to be purposefully avoided for latency tolerance reasons.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Implementation returns {@link SynchronousQueue} when maxQueueSize <= 0 or {@link LinkedBlockingQueue} when maxQueueSize > 0.\n     * \n     * @param maxQueueSize\n     *            The max size of the queue requested via properties (or system default if no properties set).\n     * @return instance of {@code BlockingQueue<Runnable>}\n     */\n    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {\n        /*\n         * We are using SynchronousQueue if maxQueueSize <= 0 (meaning a queue is not wanted).\n         * <p>\n         * SynchronousQueue will do a handoff from calling thread to worker thread and not allow queuing which is what we want.\n         * <p>\n         * Queuing results in added latency and would only occur when the thread-pool is full at which point there are latency issues\n         * and rejecting is the preferred solution.\n         */\n        if (maxQueueSize <= 0) {\n            return new SynchronousQueue<Runnable>();\n        } else {\n            return new LinkedBlockingQueue<Runnable>(maxQueueSize);\n        }\n    }\n\n    /**\n     * Provides an opportunity to wrap/decorate a {@code Callable<T>} before execution.\n     * <p>\n     * This can be used to inject additional behavior such as copying of thread state (such as {@link ThreadLocal}).\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Pass-thru that does no wrapping.\n     * \n     * @param callable\n     *            {@code Callable<T>} to be executed via a {@link ThreadPoolExecutor}\n     * @return {@code Callable<T>} either as a pass-thru or wrapping the one given\n     */\n    public <T> Callable<T> wrapCallable(Callable<T> callable) {\n        return callable;\n    }\n\n    /**\n     * Factory method to return an implementation of {@link HystrixRequestVariable} that behaves like a {@link ThreadLocal} except that it\n     * is scoped to a request instead of a thread.\n     * <p>\n     * For example, if a request starts with an HTTP request and ends with the HTTP response, then {@link HystrixRequestVariable} should\n     * be initialized at the beginning, available on any and all threads spawned during the request and then cleaned up once the HTTP request is completed.\n     * <p>\n     * If this method is implemented it is generally necessary to also implemented {@link #wrapCallable(Callable)} in order to copy state\n     * from parent to child thread.\n     * \n     * @param rv\n     *            {@link HystrixRequestVariableLifecycle} with lifecycle implementations from Hystrix\n     * @return {@code HystrixRequestVariable<T>}\n     */\n    public <T> HystrixRequestVariable<T> getRequestVariable(final HystrixRequestVariableLifecycle<T> rv) {\n        return new HystrixLifecycleForwardingRequestVariable<T>(rv);\n    }\n    \n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixConcurrencyStrategyDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\n/**\n * Default implementation of {@link HystrixConcurrencyStrategy} using standard java.util.concurrent.* implementations.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixConcurrencyStrategyDefault extends HystrixConcurrencyStrategy {\n\n    private static HystrixConcurrencyStrategyDefault INSTANCE = new HystrixConcurrencyStrategyDefault();\n\n    public static HystrixConcurrencyStrategy getInstance() {\n        return INSTANCE;\n    }\n\n    private HystrixConcurrencyStrategyDefault() {\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextCallable.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.Callable;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Wrapper around {@link Callable} that manages the {@link HystrixRequestContext} initialization and cleanup for the execution of the {@link Callable}\n * \n * @param <K>\n *            Return type of {@link Callable}\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixContextCallable<K> implements Callable<K> {\n\n    private final Callable<K> actual;\n    private final HystrixRequestContext parentThreadState;\n\n    public HystrixContextCallable(Callable<K> actual) {\n        this(HystrixPlugins.getInstance().getConcurrencyStrategy(), actual);\n    }\n\n    public HystrixContextCallable(HystrixConcurrencyStrategy concurrencyStrategy, Callable<K> actual) {\n        this.actual = concurrencyStrategy.wrapCallable(actual);\n        this.parentThreadState = HystrixRequestContext.getContextForCurrentThread();\n    }\n\n    @Override\n    public K call() throws Exception {\n        HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();\n        try {\n            // set the state of this thread to that of its parent\n            HystrixRequestContext.setContextOnCurrentThread(parentThreadState);\n            // execute actual Callable with the state of the parent\n            return actual.call();\n        } finally {\n            // restore this thread back to its original state\n            HystrixRequestContext.setContextOnCurrentThread(existingState);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextRunnable.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.Callable;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Wrapper around {@link Runnable} that manages the {@link HystrixRequestContext} initialization and cleanup for the execution of the {@link Runnable}\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixContextRunnable implements Runnable {\n\n    private final Callable<Void> actual;\n    private final HystrixRequestContext parentThreadState;\n\n    public HystrixContextRunnable(Runnable actual) {\n        this(HystrixPlugins.getInstance().getConcurrencyStrategy(), actual);\n    }\n    \n    public HystrixContextRunnable(HystrixConcurrencyStrategy concurrencyStrategy, final Runnable actual) {\n        this(concurrencyStrategy, HystrixRequestContext.getContextForCurrentThread(), actual);\n    }\n\n    public HystrixContextRunnable(final HystrixConcurrencyStrategy concurrencyStrategy, final HystrixRequestContext hystrixRequestContext, final Runnable actual) {\n        this.actual = concurrencyStrategy.wrapCallable(new Callable<Void>() {\n\n            @Override\n            public Void call() throws Exception {\n                actual.run();\n                return null;\n            }\n\n        });\n        this.parentThreadState = hystrixRequestContext;\n    }\n\n    @Override\n    public void run() {\n        HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();\n        try {\n            // set the state of this thread to that of its parent\n            HystrixRequestContext.setContextOnCurrentThread(parentThreadState);\n            // execute actual Callable with the state of the parent\n            try {\n                actual.call();\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        } finally {\n            // restore this thread back to its original state\n            HystrixRequestContext.setContextOnCurrentThread(existingState);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextScheduler.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.*;\n\nimport rx.*;\nimport rx.functions.Action0;\nimport rx.functions.Func0;\nimport rx.internal.schedulers.ScheduledAction;\nimport rx.subscriptions.*;\n\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Wrap a {@link Scheduler} so that scheduled actions are wrapped with {@link HystrixContextSchedulerAction} so that\n * the {@link HystrixRequestContext} is properly copied across threads (if they are used by the {@link Scheduler}).\n */\npublic class HystrixContextScheduler extends Scheduler {\n\n    private final HystrixConcurrencyStrategy concurrencyStrategy;\n    private final Scheduler actualScheduler;\n    private final HystrixThreadPool threadPool;\n\n    public HystrixContextScheduler(Scheduler scheduler) {\n        this.actualScheduler = scheduler;\n        this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();\n        this.threadPool = null;\n    }\n\n    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, Scheduler scheduler) {\n        this.actualScheduler = scheduler;\n        this.concurrencyStrategy = concurrencyStrategy;\n        this.threadPool = null;\n    }\n\n    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, HystrixThreadPool threadPool) {\n        this(concurrencyStrategy, threadPool, new Func0<Boolean>() {\n            @Override\n            public Boolean call() {\n                return true;\n            }\n        });\n    }\n\n    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {\n        this.concurrencyStrategy = concurrencyStrategy;\n        this.threadPool = threadPool;\n        this.actualScheduler = new ThreadPoolScheduler(threadPool, shouldInterruptThread);\n    }\n\n    @Override\n    public Worker createWorker() {\n        return new HystrixContextSchedulerWorker(actualScheduler.createWorker());\n    }\n\n    private class HystrixContextSchedulerWorker extends Worker {\n\n        private final Worker worker;\n\n        private HystrixContextSchedulerWorker(Worker actualWorker) {\n            this.worker = actualWorker;\n        }\n\n        @Override\n        public void unsubscribe() {\n            worker.unsubscribe();\n        }\n\n        @Override\n        public boolean isUnsubscribed() {\n            return worker.isUnsubscribed();\n        }\n\n        @Override\n        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {\n            if (threadPool != null) {\n                if (!threadPool.isQueueSpaceAvailable()) {\n                    throw new RejectedExecutionException(\"Rejected command because thread-pool queueSize is at rejection threshold.\");\n                }\n            }\n            return worker.schedule(new HystrixContextSchedulerAction(concurrencyStrategy, action), delayTime, unit);\n        }\n\n        @Override\n        public Subscription schedule(Action0 action) {\n            if (threadPool != null) {\n                if (!threadPool.isQueueSpaceAvailable()) {\n                    throw new RejectedExecutionException(\"Rejected command because thread-pool queueSize is at rejection threshold.\");\n                }\n            }\n            return worker.schedule(new HystrixContextSchedulerAction(concurrencyStrategy, action));\n        }\n\n    }\n\n    private static class ThreadPoolScheduler extends Scheduler {\n\n        private final HystrixThreadPool threadPool;\n        private final Func0<Boolean> shouldInterruptThread;\n\n        public ThreadPoolScheduler(HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {\n            this.threadPool = threadPool;\n            this.shouldInterruptThread = shouldInterruptThread;\n        }\n\n        @Override\n        public Worker createWorker() {\n            return new ThreadPoolWorker(threadPool, shouldInterruptThread);\n        }\n\n    }\n\n    /**\n     * Purely for scheduling work on a thread-pool.\n     * <p>\n     * This is not natively supported by RxJava as of 0.18.0 because thread-pools\n     * are contrary to sequential execution.\n     * <p>\n     * For the Hystrix case, each Command invocation has a single action so the concurrency\n     * issue is not a problem.\n     */\n    private static class ThreadPoolWorker extends Worker {\n\n        private final HystrixThreadPool threadPool;\n        private final CompositeSubscription subscription = new CompositeSubscription();\n        private final Func0<Boolean> shouldInterruptThread;\n\n        public ThreadPoolWorker(HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {\n            this.threadPool = threadPool;\n            this.shouldInterruptThread = shouldInterruptThread;\n        }\n\n        @Override\n        public void unsubscribe() {\n            subscription.unsubscribe();\n        }\n\n        @Override\n        public boolean isUnsubscribed() {\n            return subscription.isUnsubscribed();\n        }\n\n        @Override\n        public Subscription schedule(final Action0 action) {\n            if (subscription.isUnsubscribed()) {\n                // don't schedule, we are unsubscribed\n                return Subscriptions.unsubscribed();\n            }\n\n            // This is internal RxJava API but it is too useful.\n            ScheduledAction sa = new ScheduledAction(action);\n\n            subscription.add(sa);\n            sa.addParent(subscription);\n\n            ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor();\n            FutureTask<?> f = (FutureTask<?>) executor.submit(sa);\n            sa.add(new FutureCompleterWithConfigurableInterrupt(f, shouldInterruptThread, executor));\n\n            return sa;\n        }\n\n        @Override\n        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {\n            throw new IllegalStateException(\"Hystrix does not support delayed scheduling\");\n        }\n    }\n\n    /**\n     * Very similar to rx.internal.schedulers.ScheduledAction.FutureCompleter, but with configurable interrupt behavior\n     */\n    private static class FutureCompleterWithConfigurableInterrupt implements Subscription {\n        private final FutureTask<?> f;\n        private final Func0<Boolean> shouldInterruptThread;\n        private final ThreadPoolExecutor executor;\n\n        private FutureCompleterWithConfigurableInterrupt(FutureTask<?> f, Func0<Boolean> shouldInterruptThread, ThreadPoolExecutor executor) {\n            this.f = f;\n            this.shouldInterruptThread = shouldInterruptThread;\n            this.executor = executor;\n        }\n\n        @Override\n        public void unsubscribe() {\n            executor.remove(f);\n            if (shouldInterruptThread.call()) {\n                f.cancel(true);\n            } else {\n                f.cancel(false);\n            }\n        }\n\n        @Override\n        public boolean isUnsubscribed() {\n            return f.isCancelled();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextSchedulerAction.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.Callable;\n\nimport rx.functions.Action0;\nimport rx.functions.Func2;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Wrapper around {@link Func2} that manages the {@link HystrixRequestContext} initialization and cleanup for the execution of the {@link Func2}\n * \n * @param <T>\n *            Return type of {@link Func2}\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixContextSchedulerAction implements Action0 {\n\n    private final Action0 actual;\n    private final HystrixRequestContext parentThreadState;\n    private final Callable<Void> c;\n\n    public HystrixContextSchedulerAction(Action0 action) {\n        this(HystrixPlugins.getInstance().getConcurrencyStrategy(), action);\n    }\n\n    public HystrixContextSchedulerAction(final HystrixConcurrencyStrategy concurrencyStrategy, Action0 action) {\n        this.actual = action;\n        this.parentThreadState = HystrixRequestContext.getContextForCurrentThread();\n\n        this.c = concurrencyStrategy.wrapCallable(new Callable<Void>() {\n\n            @Override\n            public Void call() throws Exception {\n                HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();\n                try {\n                    // set the state of this thread to that of its parent\n                    HystrixRequestContext.setContextOnCurrentThread(parentThreadState);\n                    // execute actual Action0 with the state of the parent\n                    actual.call();\n                    return null;\n                } finally {\n                    // restore this thread back to its original state\n                    HystrixRequestContext.setContextOnCurrentThread(existingState);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void call() {\n        try {\n            c.call();\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed executing wrapped Action0\", e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixLifecycleForwardingRequestVariable.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\n/**\n * Implementation of {@link HystrixRequestVariable} which forwards to the wrapped\n * {@link HystrixRequestVariableLifecycle}.\n * <p>\n * This implementation also returns null when {@link #get()} is called while the {@link HystrixRequestContext} has not\n * been initialized rather than throwing an exception, allowing for use in a {@link HystrixConcurrencyStrategy} which\n * does not depend on an a HystrixRequestContext\n */\npublic class HystrixLifecycleForwardingRequestVariable<T> extends HystrixRequestVariableDefault<T> {\n    private final HystrixRequestVariableLifecycle<T> lifecycle;\n\n    /**\n     * Creates a HystrixRequestVariable which will return data as provided by the {@link HystrixRequestVariableLifecycle}\n     * @param lifecycle lifecycle used to provide values. Must have the same type parameter as the constructed instance.\n     */\n    public HystrixLifecycleForwardingRequestVariable(HystrixRequestVariableLifecycle<T> lifecycle) {\n        this.lifecycle = lifecycle;\n    }\n\n    /**\n     * Delegates to the wrapped {@link HystrixRequestVariableLifecycle}\n     * @return T with initial value or null if none.\n     */\n    @Override\n    public T initialValue() {\n        return lifecycle.initialValue();\n    }\n\n    /**\n     * Delegates to the wrapped {@link HystrixRequestVariableLifecycle}\n     * @param value\n     *            of request variable to allow cleanup activity.\n     *            <p>\n     *            If nothing needs to be cleaned up then nothing needs to be done in this method.\n     */\n    @Override\n    public void shutdown(T value) {\n        lifecycle.shutdown(value);\n    }\n\n    /**\n     * Return null if the {@link HystrixRequestContext} has not been initialized for the current thread.\n     * <p>\n     * If {@link HystrixRequestContext} has been initialized then call method in superclass:\n     * {@link HystrixRequestVariableDefault#get()}\n     */\n    @Override\n    public T get() {\n        if (!HystrixRequestContext.isCurrentThreadInitialized()) {\n            return null;\n        }\n        return super.get();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestContext.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.io.Closeable;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixRequestCache;\nimport com.netflix.hystrix.HystrixRequestLog;\n\n/**\n * Contains the state and manages the lifecycle of {@link HystrixRequestVariableDefault} objects that provide request scoped (rather than only thread scoped) variables so that multiple threads within\n * a\n * single request can share state:\n * <ul>\n * <li>request scoped caching as in {@link HystrixRequestCache} for de-duping {@link HystrixCommand} executions</li>\n * <li>request scoped log of all events as in {@link HystrixRequestLog}</li>\n * <li>automated batching of {@link HystrixCommand} executions within the scope of a request as in {@link HystrixCollapser}</li>\n * </ul>\n * <p>\n * If those features are not used then this does not need to be used. If those features are used then this must be initialized or a custom implementation of {@link HystrixRequestVariable} must be\n * returned from {@link HystrixConcurrencyStrategy#getRequestVariable}.\n * <p>\n * If {@link HystrixRequestVariableDefault} is used (directly or indirectly by above-mentioned features) and this context has not been initialized then an {@link IllegalStateException} will be thrown\n * with a\n * message such as: <blockquote> HystrixRequestContext.initializeContext() must be called at the beginning of each request before RequestVariable functionality can be used. </blockquote>\n * <p>\n * Example ServletFilter for initializing {@link HystrixRequestContext} at the beginning of an HTTP request and shutting down at the end:\n * \n * <blockquote>\n * \n * <pre>\n * public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n *      HystrixRequestContext context = HystrixRequestContext.initializeContext();\n *      try {\n *           chain.doFilter(request, response);\n *      } finally {\n *           context.shutdown();\n *      }\n * }\n * </pre>\n * \n * </blockquote>\n * <p>\n * You can find an implementation at <a target=\"_top\" href=\"https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet\">hystrix-contrib/hystrix-request-servlet</a> on GitHub.\n * <p>\n * <b>NOTE:</b> If <code>initializeContext()</code> is called then <code>shutdown()</code> must also be called or a memory leak will occur.\n */\npublic class HystrixRequestContext implements Closeable {\n\n    /*\n     * ThreadLocal on each thread will hold the HystrixRequestVariableState.\n     * \n     * Shutdown will clear the state inside HystrixRequestContext but not nullify the ThreadLocal on all\n     * child threads as these threads will not be known by the parent when cleanupAfterRequest() is called.\n     * \n     * However, the only thing held by those child threads until they are re-used and re-initialized is an empty\n     * HystrixRequestContext object with the ConcurrentHashMap within it nulled out since once it is nullified\n     * from the parent thread it is shared across all child threads.\n     */\n    private static ThreadLocal<HystrixRequestContext> requestVariables = new ThreadLocal<HystrixRequestContext>();\n\n    public static boolean isCurrentThreadInitialized() {\n        HystrixRequestContext context = requestVariables.get();\n        return context != null && context.state != null;\n    }\n\n    public static HystrixRequestContext getContextForCurrentThread() {\n        HystrixRequestContext context = requestVariables.get();\n        if (context != null && context.state != null) {\n            // context.state can be null when context is not null\n            // if a thread is being re-used and held a context previously, the context was shut down\n            // but the thread was not cleared\n            return context;\n        } else {\n            return null;\n        }\n    }\n\n    public static void setContextOnCurrentThread(HystrixRequestContext state) {\n        requestVariables.set(state);\n    }\n\n    /**\n     * Call this at the beginning of each request (from parent thread)\n     * to initialize the underlying context so that {@link HystrixRequestVariableDefault} can be used on any children threads and be accessible from\n     * the parent thread.\n     * <p>\n     * <b>NOTE: If this method is called then <code>shutdown()</code> must also be called or a memory leak will occur.</b>\n     * <p>\n     * See class header JavaDoc for example Servlet Filter implementation that initializes and shuts down the context.\n     */\n    public static HystrixRequestContext initializeContext() {\n        HystrixRequestContext state = new HystrixRequestContext();\n        requestVariables.set(state);\n        return state;\n    }\n\n    /*\n     * This ConcurrentHashMap should not be made publicly accessible. It is the state of RequestVariables for a given RequestContext.\n     * \n     * Only HystrixRequestVariable has a reason to be accessing this field.\n     */\n    /* package */ConcurrentHashMap<HystrixRequestVariableDefault<?>, HystrixRequestVariableDefault.LazyInitializer<?>> state = new ConcurrentHashMap<HystrixRequestVariableDefault<?>, HystrixRequestVariableDefault.LazyInitializer<?>>();\n\n    // instantiation should occur via static factory methods.\n    private HystrixRequestContext() {\n\n    }\n\n    /**\n     * Shutdown {@link HystrixRequestVariableDefault} objects in this context.\n     * <p>\n     * <b>NOTE: This must be called if <code>initializeContext()</code> was called or a memory leak will occur.</b>\n     */\n    public void shutdown() {\n        if (state != null) {\n            for (HystrixRequestVariableDefault<?> v : state.keySet()) {\n                // for each RequestVariable we call 'remove' which performs the shutdown logic\n                try {\n                    HystrixRequestVariableDefault.remove(this, v);\n                } catch (Throwable t) {\n                    HystrixRequestVariableDefault.logger.error(\"Error in shutdown, will continue with shutdown of other variables\", t);\n                }\n            }\n            // null out so it can be garbage collected even if the containing object is still\n            // being held in ThreadLocals on threads that weren't cleaned up\n            state = null;\n        }\n    }\n\n    /**\n     * Shutdown {@link HystrixRequestVariableDefault} objects in this context.\n     * <p>\n     * <b>NOTE: This must be called if <code>initializeContext()</code> was called or a memory leak will occur.</b>\n     *\n     * This method invokes <code>shutdown()</code>\n     */\n    public void close() {\n      shutdown();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestVariable.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Interface for a variable similar to {@link ThreadLocal} but scoped at the user request level.\n * <p>\n * Default implementation is {@link HystrixRequestVariableDefault} managed by {@link HystrixRequestContext}.\n * <p>\n * Custom implementations can be injected using {@link HystrixPlugins} and {@link HystrixConcurrencyStrategy#getRequestVariable}.\n * <p>\n * See JavaDoc of {@link HystrixRequestContext} for more information about functionality this enables and how to use the default implementation.\n * \n * @param <T>\n *            Type to be stored on the HystrixRequestVariable\n */\npublic interface HystrixRequestVariable<T> extends HystrixRequestVariableLifecycle<T> {\n\n    /**\n     * Retrieve current value or initialize and then return value for this variable for the current request scope.\n     * \n     * @return T value of variable for current request scope.\n     */\n    public T get();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestVariableDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Default implementation of {@link HystrixRequestVariable}. Similar to {@link ThreadLocal} but scoped at the user request level. Context is managed via {@link HystrixRequestContext}.\n * <p>\n * All statements below assume that child threads are spawned and initialized with the use of {@link HystrixContextCallable} or {@link HystrixContextRunnable} which capture state from a parent thread\n * and propagate to the child thread.\n * <p>\n * Characteristics that differ from ThreadLocal:\n * <ul>\n * <li>HystrixRequestVariable context must be initialized at the beginning of every request by {@link HystrixRequestContext#initializeContext}</li>\n * <li>HystrixRequestVariables attached to a thread will be cleared at the end of every user request by {@link HystrixRequestContext#shutdown} which execute {@link #remove} for each\n * HystrixRequestVariable</li>\n * <li>HystrixRequestVariables have a {@link #shutdown} lifecycle method that gets called at the end of every user request (invoked when {@link HystrixRequestContext#shutdown} is called) to allow for\n * resource cleanup.</li>\n * <li>HystrixRequestVariables are copied (by reference) to child threads via the {@link HystrixRequestContext#getContextForCurrentThread} and {@link HystrixRequestContext#setContextOnCurrentThread}\n * functionality.</li>\n * <li>HystrixRequestVariables created on a child thread are available on sibling and parent threads.</li>\n * <li>HystrixRequestVariables created on a child thread will be cleaned up by the parent thread via the {@link #shutdown} method.</li>\n * </ul>\n * \n * <p>\n * Note on thread-safety: By design a HystrixRequestVariables is intended to be accessed by all threads in a user request, thus anything stored in a HystrixRequestVariables must be thread-safe and\n * plan on being accessed/mutated concurrently.\n * <p>\n * For example, a HashMap would likely not be a good choice for a RequestVariable value, but ConcurrentHashMap would.\n * \n * @param <T>\n *            Type to be stored on the HystrixRequestVariable\n *            <p>\n *            Example 1: {@code HystrixRequestVariable<ConcurrentHashMap<String, DataObject>>} <p>\n *            Example 2: {@code HystrixRequestVariable<PojoThatIsThreadSafe>}\n * \n * @ExcludeFromJavadoc\n * @ThreadSafe\n */\npublic class HystrixRequestVariableDefault<T> implements HystrixRequestVariable<T> {\n    static final Logger logger = LoggerFactory.getLogger(HystrixRequestVariableDefault.class);\n\n    /**\n     * Creates a new HystrixRequestVariable that will exist across all threads\n     * within a {@link HystrixRequestContext}\n     */\n    public HystrixRequestVariableDefault() {\n    }\n\n    /**\n     * Get the current value for this variable for the current request context.\n     * \n     * @return the value of the variable for the current request,\n     *         or null if no value has been set and there is no initial value\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T get() {\n        if (HystrixRequestContext.getContextForCurrentThread() == null) {\n            throw new IllegalStateException(HystrixRequestContext.class.getSimpleName() + \".initializeContext() must be called at the beginning of each request before RequestVariable functionality can be used.\");\n        }\n        ConcurrentHashMap<HystrixRequestVariableDefault<?>, LazyInitializer<?>> variableMap = HystrixRequestContext.getContextForCurrentThread().state;\n\n        // short-circuit the synchronized path below if we already have the value in the ConcurrentHashMap\n        LazyInitializer<?> v = variableMap.get(this);\n        if (v != null) {\n            return (T) v.get();\n        }\n\n        /*\n         * Optimistically create a LazyInitializer to put into the ConcurrentHashMap.\n         * \n         * The LazyInitializer will not invoke initialValue() unless the get() method is invoked\n         * so we can optimistically instantiate LazyInitializer and then discard for garbage collection\n         * if the putIfAbsent fails.\n         * \n         * Whichever instance of LazyInitializer succeeds will then have get() invoked which will call\n         * the initialValue() method once-and-only-once.\n         */\n        LazyInitializer<T> l = new LazyInitializer<T>(this);\n        LazyInitializer<?> existing = variableMap.putIfAbsent(this, l);\n        if (existing == null) {\n            /*\n             * We won the thread-race so can use 'l' that we just created.\n             */\n            return l.get();\n        } else {\n            /*\n             * We lost the thread-race so let 'l' be garbage collected and instead return 'existing'\n             */\n            return (T) existing.get();\n        }\n    }\n\n    /**\n     * Computes the initial value of the HystrixRequestVariable in a request.\n     * <p>\n     * This is called the first time the value of the HystrixRequestVariable is fetched in a request. Override this to provide an initial value for a HystrixRequestVariable on each request on which it\n     * is used.\n     * \n     * The default implementation returns null.\n     * \n     * @return initial value of the HystrixRequestVariable to use for the instance being constructed\n     */\n    public T initialValue() {\n        return null;\n    }\n\n    /**\n     * Sets the value of the HystrixRequestVariable for the current request context.\n     * <p>\n     * Note, if a value already exists, the set will result in overwriting that value. It is up to the caller to ensure the existing value is cleaned up. The {@link #shutdown} method will not be\n     * called\n     * \n     * @param value\n     *            the value to set\n     */\n    public void set(T value) {\n        HystrixRequestContext.getContextForCurrentThread().state.put(this, new LazyInitializer<T>(this, value));\n    }\n\n    /**\n     * Removes the value of the HystrixRequestVariable from the current request.\n     * <p>\n     * This will invoke {@link #shutdown} if implemented.\n     * <p>\n     * If the value is subsequently fetched in the thread, the {@link #initialValue} method will be called again.\n     */\n    public void remove() {\n        if (HystrixRequestContext.getContextForCurrentThread() != null) {\n            remove(HystrixRequestContext.getContextForCurrentThread(), this);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    /* package */static <T> void remove(HystrixRequestContext context, HystrixRequestVariableDefault<T> v) {\n        // remove first so no other threads get it\n        LazyInitializer<?> o = context.state.remove(v);\n        if (o != null) {\n            // this thread removed it so let's execute shutdown\n            v.shutdown((T) o.get());\n        }\n    }\n\n    /**\n     * Provide life-cycle hook for a HystrixRequestVariable implementation to perform cleanup\n     * before the HystrixRequestVariable is removed from the current thread.\n     * <p>\n     * This is executed at the end of each user request when {@link HystrixRequestContext#shutdown} is called or whenever {@link #remove} is invoked.\n     * <p>\n     * By default does nothing.\n     * <p>\n     * NOTE: Do not call <code>get()</code> from within this method or <code>initialValue()</code> will be invoked again. The current value is passed in as an argument.\n     * \n     * @param value\n     *            the value of the HystrixRequestVariable being removed\n     */\n    public void shutdown(T value) {\n        // do nothing by default\n    }\n\n    /**\n     * Holder for a value that can be derived from the {@link HystrixRequestVariableDefault#initialValue} method that needs\n     * to be executed once-and-only-once.\n     * <p>\n     * This class can be instantiated and garbage collected without calling initialValue() as long as the get() method is not invoked and can thus be used with compareAndSet in\n     * ConcurrentHashMap.putIfAbsent and allow \"losers\" in a thread-race to be discarded.\n     * \n     * @param <T>\n     */\n    /* package */static final class LazyInitializer<T> {\n        // @GuardedBy(\"synchronization on get() or construction\")\n        private T value;\n\n        /*\n         * Boolean to ensure only-once initialValue() execution instead of using\n         * a null check in case initialValue() returns null\n         */\n        // @GuardedBy(\"synchronization on get() or construction\")\n        private boolean initialized = false;\n\n        private final HystrixRequestVariableDefault<T> rv;\n\n        private LazyInitializer(HystrixRequestVariableDefault<T> rv) {\n            this.rv = rv;\n        }\n\n        private LazyInitializer(HystrixRequestVariableDefault<T> rv, T value) {\n            this.rv = rv;\n            this.value = value;\n            this.initialized = true;\n        }\n\n        public synchronized T get() {\n            if (!initialized) {\n                value = rv.initialValue();\n                initialized = true;\n            }\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestVariableHolder.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Factory that encompasses functionality of {@link HystrixRequestVariable} for internal Hystrix code.\n * <p>\n * This is used as a layer between the actual {@link HystrixRequestVariable} and calling code to allow injected implementations of {@link HystrixConcurrencyStrategy}.\n * <p>\n * Typically a {@link HystrixRequestVariable} would be statically referenced (similar to a ThreadLocal) but to allow dynamic injection we instead statically reference this class which can then\n * dynamically fetch the correct implementation and statically retain an instance across threads within a context (such as {@link HystrixRequestContext}.\n * \n * @param <T>\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixRequestVariableHolder<T> {\n\n    static final Logger logger = LoggerFactory.getLogger(HystrixRequestVariableHolder.class);\n\n    private static ConcurrentHashMap<RVCacheKey, HystrixRequestVariable<?>> requestVariableInstance = new ConcurrentHashMap<RVCacheKey, HystrixRequestVariable<?>>();\n\n    private final HystrixRequestVariableLifecycle<T> lifeCycleMethods;\n\n    public HystrixRequestVariableHolder(HystrixRequestVariableLifecycle<T> lifeCycleMethods) {\n        this.lifeCycleMethods = lifeCycleMethods;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T get(HystrixConcurrencyStrategy concurrencyStrategy) {\n        /*\n         * 1) Fetch RequestVariable implementation from cache.\n         * 2) If no implementation is found in cache then construct from factory.\n         * 3) Cache implementation from factory as each object instance needs to be statically cached to be relevant across threads.\n         */\n        RVCacheKey key = new RVCacheKey(this, concurrencyStrategy);\n        HystrixRequestVariable<?> rvInstance = requestVariableInstance.get(key);\n        if (rvInstance == null) {\n            requestVariableInstance.putIfAbsent(key, concurrencyStrategy.getRequestVariable(lifeCycleMethods));\n            /*\n             * A safety check to help debug problems if someone starts injecting dynamically created HystrixConcurrencyStrategy instances - which should not be done and has no good reason to be done.\n             * \n             * The 100 value is arbitrary ... just a number far higher than we should see.\n             */\n            if (requestVariableInstance.size() > 100) {\n                logger.warn(\"Over 100 instances of HystrixRequestVariable are being stored. This is likely the sign of a memory leak caused by using unique instances of HystrixConcurrencyStrategy instead of a single instance.\");\n            }\n        }\n\n        return (T) requestVariableInstance.get(key).get();\n    }\n\n    private static class RVCacheKey {\n\n        private final HystrixRequestVariableHolder<?> rvHolder;\n        private final HystrixConcurrencyStrategy concurrencyStrategy;\n\n        private RVCacheKey(HystrixRequestVariableHolder<?> rvHolder, HystrixConcurrencyStrategy concurrencyStrategy) {\n            this.rvHolder = rvHolder;\n            this.concurrencyStrategy = concurrencyStrategy;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + ((concurrencyStrategy == null) ? 0 : concurrencyStrategy.hashCode());\n            result = prime * result + ((rvHolder == null) ? 0 : rvHolder.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj)\n                return true;\n            if (obj == null)\n                return false;\n            if (getClass() != obj.getClass())\n                return false;\n            RVCacheKey other = (RVCacheKey) obj;\n            if (concurrencyStrategy == null) {\n                if (other.concurrencyStrategy != null)\n                    return false;\n            } else if (!concurrencyStrategy.equals(other.concurrencyStrategy))\n                return false;\n            if (rvHolder == null) {\n                if (other.rvHolder != null)\n                    return false;\n            } else if (!rvHolder.equals(other.rvHolder))\n                return false;\n            return true;\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixRequestVariableLifecycle.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\n/**\n * Interface for lifecycle methods that are then executed by an implementation of {@link HystrixRequestVariable}.\n * \n * @param <T>\n */\npublic interface HystrixRequestVariableLifecycle<T> {\n\n    /**\n     * Invoked when {@link HystrixRequestVariable#get()} is first called.\n     * <p>\n     * When using the default implementation this is invoked when {@link HystrixRequestVariableDefault#get()} is called.\n     * \n     * @return T with initial value or null if none.\n     */\n    public T initialValue();\n\n    /**\n     * Invoked when request scope is shutdown to allow for cleanup.\n     * <p>\n     * When using the default implementation this is invoked when {@link HystrixRequestContext#shutdown()} is called.\n     * <p>\n     * The {@link HystrixRequestVariable#get()} method should not be called from within this method as it will result in {@link #initialValue()} being called again.\n     * \n     * @param value\n     *            of request variable to allow cleanup activity.\n     *            <p>\n     *            If nothing needs to be cleaned up then nothing needs to be done in this method.\n     */\n    public void shutdown(T value);\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/concurrency/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Strategy definition for concurrency related behavior and default implementation.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.strategy.concurrency;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/eventnotifier/HystrixEventNotifier.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.eventnotifier;\n\nimport java.util.List;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Abstract EventNotifier that allows receiving notifications for different events with default implementations.\n * <p>\n * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a\n * href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n * <p>\n * <b>Note on thread-safety and performance</b>\n * <p>\n * A single implementation of this class will be used globally so methods on this class will be invoked concurrently from multiple threads so all functionality must be thread-safe.\n * <p>\n * Methods are also invoked synchronously and will add to execution time of the commands so all behavior should be fast. If anything time-consuming is to be done it should be spawned asynchronously\n * onto separate worker threads.\n */\npublic abstract class HystrixEventNotifier {\n\n    /**\n     * Called for every event fired.\n     * <p>\n     * <b>Default Implementation: </b> Does nothing\n     * \n     * @param eventType event type\n     * @param key event key\n     */\n    public void markEvent(HystrixEventType eventType, HystrixCommandKey key) {\n        // do nothing\n    }\n\n    /**\n     * Called after a command is executed using thread isolation.\n     * <p>\n     * Will not get called if a command is rejected, short-circuited etc.\n     * <p>\n     * <b>Default Implementation: </b> Does nothing\n     * \n     * @param key\n     *            {@link HystrixCommandKey} of command instance.\n     * @param isolationStrategy\n     *            {@link ExecutionIsolationStrategy} the isolation strategy used by the command when executed\n     * @param duration\n     *            time in milliseconds of executing <code>run()</code> method\n     * @param eventsDuringExecution\n     *            {@code List<HystrixEventType>} of events occurred during execution.\n     */\n    public void markCommandExecution(HystrixCommandKey key, ExecutionIsolationStrategy isolationStrategy, int duration, List<HystrixEventType> eventsDuringExecution) {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/eventnotifier/HystrixEventNotifierDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.eventnotifier;\n\n\n/**\n * Default implementations of {@link HystrixEventNotifier} that does nothing.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixEventNotifierDefault extends HystrixEventNotifier {\n\n    private static HystrixEventNotifierDefault INSTANCE = new HystrixEventNotifierDefault();\n\n    private HystrixEventNotifierDefault() {\n\n    }\n\n    public static HystrixEventNotifier getInstance() {\n        return INSTANCE;\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/eventnotifier/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Strategy definition for event notification.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.strategy.eventnotifier;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/executionhook/HystrixCommandExecutionHook.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.executionhook;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.HystrixInvokable;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException.FailureType;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Abstract ExecutionHook with invocations at different lifecycle points of {@link HystrixCommand}\n * and {@link HystrixObservableCommand} execution with default no-op implementations.\n * <p>\n * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a\n * href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n * <p>\n * <b>Note on thread-safety and performance</b>\n * <p>\n * A single implementation of this class will be used globally so methods on this class will be invoked concurrently from multiple threads so all functionality must be thread-safe.\n * <p>\n * Methods are also invoked synchronously and will add to execution time of the commands so all behavior should be fast. If anything time-consuming is to be done it should be spawned asynchronously\n * onto separate worker threads.\n * \n * @since 1.2\n * */\npublic abstract class HystrixCommandExecutionHook {\n\n    /**\n     * Invoked before {@link HystrixInvokable} begins executing.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.2\n     */\n    public <T> void onStart(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked when {@link HystrixInvokable} emits a value.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param value value emitted\n     *\n     * @since 1.4\n     */\n    public <T> T onEmit(HystrixInvokable<T> commandInstance, T value) {\n        return value; //by default, just pass through\n    }\n\n    /**\n     * Invoked when {@link HystrixInvokable} fails with an Exception.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param failureType {@link FailureType} enum representing which type of error\n     * @param e exception object\n     *\n     * @since 1.2\n     */\n    public <T> Exception onError(HystrixInvokable<T> commandInstance, FailureType failureType, Exception e) {\n        return e; //by default, just pass through\n    }\n\n    /**\n     * Invoked when {@link HystrixInvokable} finishes a successful execution.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.4\n     */\n    public <T> void onSuccess(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked at start of thread execution when {@link HystrixCommand} is executed using {@link ExecutionIsolationStrategy#THREAD}.\n     *\n     * @param commandInstance The executing HystrixCommand instance.\n     *\n     * @since 1.2\n     */\n    public <T> void onThreadStart(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked at completion of thread execution when {@link HystrixCommand} is executed using {@link ExecutionIsolationStrategy#THREAD}.\n     * This will get invoked whenever the Hystrix thread is done executing, regardless of whether the thread finished\n     * naturally, or was unsubscribed externally\n     *\n     * @param commandInstance The executing HystrixCommand instance.\n     *\n     * @since 1.2\n     */\n    public <T> void onThreadComplete(HystrixInvokable<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * Invoked when the user-defined execution method in {@link HystrixInvokable} starts.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.4\n     */\n    public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked when the user-defined execution method in {@link HystrixInvokable} emits a value.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param value value emitted\n     *\n     * @since 1.4\n     */\n    public <T> T onExecutionEmit(HystrixInvokable<T> commandInstance, T value) {\n        return value; //by default, just pass through\n    }\n\n    /**\n     * Invoked when the user-defined execution method in {@link HystrixInvokable} fails with an Exception.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param e exception object\n     *\n     * @since 1.4\n     */\n    public <T> Exception onExecutionError(HystrixInvokable<T> commandInstance, Exception e) {\n        return e; //by default, just pass through\n    }\n\n    /**\n     * Invoked when the user-defined execution method in {@link HystrixInvokable} completes successfully.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.4\n     */\n    public <T> void onExecutionSuccess(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked when the fallback method in {@link HystrixInvokable} starts.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.2\n     */\n    public <T> void onFallbackStart(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked when the fallback method in {@link HystrixInvokable} emits a value.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param value value emitted\n     *\n     * @since 1.4\n     */\n    public <T> T onFallbackEmit(HystrixInvokable<T> commandInstance, T value) {\n        return value; //by default, just pass through\n    }\n\n    /**\n     * Invoked when the fallback method in {@link HystrixInvokable} fails with an Exception.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     * @param e exception object\n     *\n     * @since 1.2\n     */\n    public <T> Exception onFallbackError(HystrixInvokable<T> commandInstance, Exception e) {\n        //by default, just pass through\n        return e;\n    }\n\n    /**\n     * Invoked when the user-defined execution method in {@link HystrixInvokable} completes successfully.\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.4\n     */\n    public <T> void onFallbackSuccess(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked when the command response is found in the {@link com.netflix.hystrix.HystrixRequestCache}.\n     *\n     * @param commandInstance The executing HystrixCommand\n     *\n     * @since 1.4\n     */\n    public <T> void onCacheHit(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * Invoked with the command is unsubscribed before a terminal state\n     *\n     * @param commandInstance The executing HystrixInvokable instance.\n     *\n     * @since 1.5.9\n     */\n    public <T> void onUnsubscribe(HystrixInvokable<T> commandInstance) {\n        //do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionStart}.\n     *\n     * Invoked before {@link HystrixCommand#run()} is about to be executed.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onRunStart(HystrixCommand<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionStart}.\n     *\n     * Invoked before {@link HystrixCommand#run()} is about to be executed.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     *\n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onRunStart(HystrixInvokable<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionEmit} if you want to add a hook for each value emitted by the command\n     * or to {@link #onExecutionSuccess} if you want to add a hook when the command successfully executes\n     *\n     * Invoked after successful execution of {@link HystrixCommand#run()} with response value.\n     * In a {@link HystrixCommand} using {@link ExecutionIsolationStrategy#THREAD}, this will get invoked if the Hystrix thread\n     * successfully runs, regardless of whether the calling thread encountered a timeout.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param response\n     *            from {@link HystrixCommand#run()}\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onRunSuccess(HystrixCommand<T> commandInstance, T response) {\n        // pass-thru by default\n        return response;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionEmit} if you want to add a hook for each value emitted by the command\n     * or to {@link #onExecutionSuccess} if you want to add a hook when the command successfully executes\n     *\n     * Invoked after successful execution of {@link HystrixCommand#run()} with response value.\n     * In a {@link HystrixCommand} using {@link ExecutionIsolationStrategy#THREAD}, this will get invoked if the Hystrix thread\n     * successfully runs, regardless of whether the calling thread encountered a timeout.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param response\n     *            from {@link HystrixCommand#run()}\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     *\n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onRunSuccess(HystrixInvokable<T> commandInstance, T response) {\n        // pass-thru by default\n        return response;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionError}\n     *\n     * Invoked after failed execution of {@link HystrixCommand#run()} with thrown Exception.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param e\n     *            Exception thrown by {@link HystrixCommand#run()}\n     * @return Exception that can be decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> Exception onRunError(HystrixCommand<T> commandInstance, Exception e) {\n        // pass-thru by default\n        return e;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onExecutionError}\n     *\n     * Invoked after failed execution of {@link HystrixCommand#run()} with thrown Exception.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param e\n     *            Exception thrown by {@link HystrixCommand#run()}\n     * @return Exception that can be decorated, replaced or just returned as a pass-thru.\n     *\n     * @since 1.2\n     */\n    @Deprecated\n    public <T> Exception onRunError(HystrixInvokable<T> commandInstance, Exception e) {\n        // pass-thru by default\n        return e;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onFallbackStart}\n     *\n     * Invoked before {@link HystrixCommand#getFallback()} is about to be executed.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onFallbackStart(HystrixCommand<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onFallbackEmit} if you want to write a hook that handles each emitted fallback value\n     * or to {@link #onFallbackSuccess} if you want to write a hook that handles success of the fallback method\n     *\n     * Invoked after successful execution of {@link HystrixCommand#getFallback()} with response value.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param fallbackResponse\n     *            from {@link HystrixCommand#getFallback()}\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onFallbackSuccess(HystrixCommand<T> commandInstance, T fallbackResponse) {\n        // pass-thru by default\n        return fallbackResponse;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onFallbackEmit} if you want to write a hook that handles each emitted fallback value\n     * or to {@link #onFallbackSuccess} if you want to write a hook that handles success of the fallback method\n     *\n     * Invoked after successful execution of {@link HystrixCommand#getFallback()} with response value.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param fallbackResponse\n     *            from {@link HystrixCommand#getFallback()}\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     *\n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onFallbackSuccess(HystrixInvokable<T> commandInstance, T fallbackResponse) {\n        // pass-thru by default\n        return fallbackResponse;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onFallbackError}.\n     *\n     * Invoked after failed execution of {@link HystrixCommand#getFallback()} with thrown exception.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param e\n     *            Exception thrown by {@link HystrixCommand#getFallback()}\n     * @return Exception that can be decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> Exception onFallbackError(HystrixCommand<T> commandInstance, Exception e) {\n        // pass-thru by default\n        return e;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onStart}.\n     *\n     * Invoked before {@link HystrixCommand} executes.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onStart(HystrixCommand<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onEmit} if you want to write a hook that handles each emitted command value\n     * or to {@link #onSuccess} if you want to write a hook that handles success of the command\n     *\n     * Invoked after completion of {@link HystrixCommand} execution that results in a response.\n     * <p>\n     * The response can come either from {@link HystrixCommand#run()} or {@link HystrixCommand#getFallback()}.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param response\n     *            from {@link HystrixCommand#run()} or {@link HystrixCommand#getFallback()}.\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onComplete(HystrixCommand<T> commandInstance, T response) {\n        // pass-thru by default\n        return response;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onEmit} if you want to write a hook that handles each emitted command value\n     * or to {@link #onSuccess} if you want to write a hook that handles success of the command\n     *\n     * Invoked after completion of {@link HystrixCommand} execution that results in a response.\n     * <p>\n     * The response can come either from {@link HystrixCommand#run()} or {@link HystrixCommand#getFallback()}.\n     *\n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param response\n     *            from {@link HystrixCommand#run()} or {@link HystrixCommand#getFallback()}.\n     * @return T response object that can be modified, decorated, replaced or just returned as a pass-thru.\n     *\n     * @since 1.2\n     */\n    @Deprecated\n    public <T> T onComplete(HystrixInvokable<T> commandInstance, T response) {\n        // pass-thru by default\n        return response;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onError}.\n     *\n     * Invoked after failed completion of {@link HystrixCommand} execution.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * @param failureType\n     *            {@link FailureType} representing the type of failure that occurred.\n     *            <p>\n     *            See {@link HystrixRuntimeException} for more information.\n     * @param e\n     *            Exception thrown by {@link HystrixCommand}\n     * @return Exception that can be decorated, replaced or just returned as a pass-thru.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> Exception onError(HystrixCommand<T> commandInstance, FailureType failureType, Exception e) {\n        // pass-thru by default\n        return e;\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onThreadStart}.\n     *\n     * Invoked at start of thread execution when {@link HystrixCommand} is executed using {@link ExecutionIsolationStrategy#THREAD}.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onThreadStart(HystrixCommand<T> commandInstance) {\n        // do nothing by default\n    }\n\n    /**\n     * DEPRECATED: Change usages of this to {@link #onThreadComplete}.\n     *\n     * Invoked at completion of thread execution when {@link HystrixCommand} is executed using {@link ExecutionIsolationStrategy#THREAD}.\n     * This will get invoked if the Hystrix thread successfully executes, regardless of whether the calling thread\n     * encountered a timeout.\n     * \n     * @param commandInstance\n     *            The executing HystrixCommand instance.\n     * \n     * @since 1.2\n     */\n    @Deprecated\n    public <T> void onThreadComplete(HystrixCommand<T> commandInstance) {\n        // do nothing by default\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/executionhook/HystrixCommandExecutionHookDefault.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.executionhook;\n\n/**\n * Default implementations of {@link HystrixCommandExecutionHook} that does nothing.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixCommandExecutionHookDefault extends HystrixCommandExecutionHook {\n\n    private static HystrixCommandExecutionHookDefault INSTANCE = new HystrixCommandExecutionHookDefault();\n\n    private HystrixCommandExecutionHookDefault() {\n\n    }\n\n    public static HystrixCommandExecutionHook getInstance() {\n        return INSTANCE;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/executionhook/package-info.java",
    "content": "/**\n * Copyright 2013 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Strategy definition for execution hook.\n * \n * @since 1.2.0\n */\npackage com.netflix.hystrix.strategy.executionhook;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisher.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Abstract class with default implementations of Factory methods for creating \"Metrics Publisher\" instances for getting metrics and other related data\n * exposed, published or otherwise retrievable by external systems such as Servo (https://github.com/Netflix/servo)\n * for monitoring and statistical purposes.\n * <p>\n * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a\n * href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n */\npublic abstract class HystrixMetricsPublisher {\n\n    // TODO should this have cacheKey functionality like HystrixProperties does?\n    // I think we do otherwise dynamically provided owner and properties won't work\n    // a custom override would need the caching strategy for properties/publisher/owner etc to be in sync\n\n    /**\n     * Construct an implementation of {@link HystrixMetricsPublisherCommand} for {@link HystrixCommand} instances having key {@link HystrixCommandKey}.\n     * <p>\n     * This will be invoked once per {@link HystrixCommandKey} instance.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Return instance of {@link HystrixMetricsPublisherCommandDefault}\n     * \n     * @param commandKey\n     *            {@link HystrixCommandKey} representing the name or type of {@link HystrixCommand}\n     * @param commandGroupKey\n     *            {@link HystrixCommandGroupKey} of {@link HystrixCommand}\n     * @param metrics\n     *            {@link HystrixCommandMetrics} instance tracking metrics for {@link HystrixCommand} instances having the key as defined by {@link HystrixCommandKey}\n     * @param circuitBreaker\n     *            {@link HystrixCircuitBreaker} instance for {@link HystrixCommand} instances having the key as defined by {@link HystrixCommandKey}\n     * @param properties\n     *            {@link HystrixCommandProperties} instance for {@link HystrixCommand} instances having the key as defined by {@link HystrixCommandKey}\n     * @return instance of {@link HystrixMetricsPublisherCommand} that will have its <code>initialize</code> method invoked once.\n     */\n    public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        return new HystrixMetricsPublisherCommandDefault(commandKey, commandGroupKey, metrics, circuitBreaker, properties);\n    }\n\n    /**\n     * Construct an implementation of {@link HystrixMetricsPublisherThreadPool} for {@link HystrixThreadPool} instances having key {@link HystrixThreadPoolKey}.\n     * <p>\n     * This will be invoked once per {@link HystrixThreadPoolKey} instance.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Return instance of {@link HystrixMetricsPublisherThreadPoolDefault}\n     * \n     * @param threadPoolKey\n     *            {@link HystrixThreadPoolKey} representing the name or type of {@link HystrixThreadPool}\n     * @param metrics\n     *            {@link HystrixThreadPoolMetrics} instance tracking metrics for the {@link HystrixThreadPool} instance having the key as defined by {@link HystrixThreadPoolKey}\n     * @param properties\n     *            {@link HystrixThreadPoolProperties} instance for the {@link HystrixThreadPool} instance having the key as defined by {@link HystrixThreadPoolKey}\n     * @return instance of {@link HystrixMetricsPublisherThreadPool} that will have its <code>initialize</code> method invoked once.\n     */\n    public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        return new HystrixMetricsPublisherThreadPoolDefault(threadPoolKey, metrics, properties);\n    }\n\n    /**\n     * Construct an implementation of {@link HystrixMetricsPublisherCollapser} for {@link HystrixCollapser} instances having key {@link HystrixCollapserKey}.\n     * <p>\n     * This will be invoked once per {@link HystrixCollapserKey} instance.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Return instance of {@link HystrixMetricsPublisherCollapserDefault}\n     *\n     * @param collapserKey\n     *            {@link HystrixCollapserKey} representing the name or type of {@link HystrixCollapser}\n     * @param metrics\n     *            {@link HystrixCollapserMetrics} instance tracking metrics for the {@link HystrixCollapser} instance having the key as defined by {@link HystrixCollapserKey}\n     * @param properties\n     *            {@link HystrixCollapserProperties} instance for the {@link HystrixCollapser} instance having the key as defined by {@link HystrixCollapserKey}\n     * @return instance of {@link HystrixMetricsPublisherCollapser} that will have its <code>initialize</code> method invoked once.\n     */\n    public HystrixMetricsPublisherCollapser getMetricsPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        return new HystrixMetricsPublisherCollapserDefault(collapserKey, metrics, properties);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherCollapser.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixCollapser;\n\n/**\n * Metrics publisher for a {@link HystrixCollapser} that will be constructed by an implementation of {@link HystrixMetricsPublisher}.\n * <p>\n * Instantiation of implementations of this interface should NOT allocate resources that require shutdown, register listeners or other such global state changes.\n * <p>\n * The <code>initialize()</code> method will be called once-and-only-once to indicate when this instance can register with external services, start publishing metrics etc.\n * <p>\n * Doing this logic in the constructor could result in memory leaks, double-publishing and other such behavior because this can be optimistically constructed more than once and \"extras\" discarded with\n * only one actually having <code>initialize()</code> called on it.\n */\npublic interface HystrixMetricsPublisherCollapser {\n\n    // TODO should the arguments be given via initialize rather than constructor so people can't accidentally do it wrong?\n\n    public void initialize();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherCollapserDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\n\n/**\n * Default implementation of {@link HystrixMetricsPublisherCollapser} that does nothing.\n * <p>\n * See <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">Wiki docs</a> about plugins for more information.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixMetricsPublisherCollapserDefault implements HystrixMetricsPublisherCollapser {\n\n    public HystrixMetricsPublisherCollapserDefault(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        // do nothing by default\n    }\n\n    @Override\n    public void initialize() {\n        // do nothing by default\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixCommand;\n\n/**\n * Metrics publisher for a {@link HystrixCommand} that will be constructed by an implementation of {@link HystrixMetricsPublisher}.\n * <p>\n * Instantiation of implementations of this interface should NOT allocate resources that require shutdown, register listeners or other such global state changes.\n * <p>\n * The <code>initialize()</code> method will be called once-and-only-once to indicate when this instance can register with external services, start publishing metrics etc.\n * <p>\n * Doing this logic in the constructor could result in memory leaks, double-publishing and other such behavior because this can be optimistically constructed more than once and \"extras\" discarded with\n * only one actually having <code>initialize()</code> called on it.\n */\npublic interface HystrixMetricsPublisherCommand {\n\n    // TODO should the arguments be given via initialize rather than constructor so they can't accidentally do it wrong?\n    \n    public void initialize();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherCommandDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\n\n/**\n * Default implementation of {@link HystrixMetricsPublisherCommand} that does nothing.\n * <p>\n * See <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">Wiki docs</a> about plugins for more information.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixMetricsPublisherCommandDefault implements HystrixMetricsPublisherCommand {\n\n    public HystrixMetricsPublisherCommandDefault(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        // do nothing by default\n    }\n\n    @Override\n    public void initialize() {\n        // do nothing by default\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\n/**\n * Default implementation of {@link HystrixMetricsPublisher}.\n * <p>\n * See <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">Wiki docs</a> about plugins for more information.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixMetricsPublisherDefault extends HystrixMetricsPublisher {\n\n    private static HystrixMetricsPublisherDefault INSTANCE = new HystrixMetricsPublisherDefault();\n\n    public static HystrixMetricsPublisher getInstance() {\n        return INSTANCE;\n    }\n\n    private HystrixMetricsPublisherDefault() {\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherFactory.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Factory for retrieving metrics publisher implementations.\n * <p>\n * This uses given {@link HystrixMetricsPublisher} implementations to construct publisher instances and caches each instance according to the cache key provided.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixMetricsPublisherFactory {\n\n    /**\n     * The SINGLETON instance for real use.\n     * <p>\n     * Unit tests will create instance methods for testing and injecting different publishers.\n     */\n    private static HystrixMetricsPublisherFactory SINGLETON = new HystrixMetricsPublisherFactory();\n\n    /**\n     * Get an instance of {@link HystrixMetricsPublisherThreadPool} with the given factory {@link HystrixMetricsPublisher} implementation for each {@link HystrixThreadPool} instance.\n     *\n     * @param threadPoolKey\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForThreadPool} implementation\n     * @param metrics\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForThreadPool} implementation\n     * @param properties\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForThreadPool} implementation\n     * @return {@link HystrixMetricsPublisherThreadPool} instance\n     */\n    public static HystrixMetricsPublisherThreadPool createOrRetrievePublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        return SINGLETON.getPublisherForThreadPool(threadPoolKey, metrics, properties);\n    }\n\n    /**\n     * Get an instance of {@link HystrixMetricsPublisherCommand} with the given factory {@link HystrixMetricsPublisher} implementation for each {@link HystrixCommand} instance.\n     * \n     * @param commandKey\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCommand} implementation\n     * @param commandOwner\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCommand} implementation\n     * @param metrics\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCommand} implementation\n     * @param circuitBreaker\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCommand} implementation\n     * @param properties\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCommand} implementation\n     * @return {@link HystrixMetricsPublisherCommand} instance\n     */\n    public static HystrixMetricsPublisherCommand createOrRetrievePublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandOwner, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        return SINGLETON.getPublisherForCommand(commandKey, commandOwner, metrics, circuitBreaker, properties);\n    }\n\n    /**\n     * Resets the SINGLETON object.\n     * Clears all state from publishers. If new requests come in instances will be recreated.\n     *\n     */\n    public static void reset() {\n        SINGLETON = new HystrixMetricsPublisherFactory();\n        SINGLETON.commandPublishers.clear();\n        SINGLETON.threadPoolPublishers.clear();\n        SINGLETON.collapserPublishers.clear();\n    }\n\n    /* package */ HystrixMetricsPublisherFactory()  {}\n\n    // String is CommandKey.name() (we can't use CommandKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private final ConcurrentHashMap<String, HystrixMetricsPublisherCommand> commandPublishers = new ConcurrentHashMap<String, HystrixMetricsPublisherCommand>();\n\n    /* package */ HystrixMetricsPublisherCommand getPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandOwner, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixMetricsPublisherCommand publisher = commandPublishers.get(commandKey.name());\n        if (publisher != null) {\n            return publisher;\n        } else {\n            synchronized (this) {\n                HystrixMetricsPublisherCommand existingPublisher = commandPublishers.get(commandKey.name());\n                if (existingPublisher != null) {\n                    return existingPublisher;\n                } else {\n                    HystrixMetricsPublisherCommand newPublisher = HystrixPlugins.getInstance().getMetricsPublisher().getMetricsPublisherForCommand(commandKey, commandOwner, metrics, circuitBreaker, properties);\n                    commandPublishers.putIfAbsent(commandKey.name(), newPublisher);\n                    newPublisher.initialize();\n                    return newPublisher;\n                }\n            }\n        }\n    }\n\n    // String is ThreadPoolKey.name() (we can't use ThreadPoolKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private final ConcurrentHashMap<String, HystrixMetricsPublisherThreadPool> threadPoolPublishers = new ConcurrentHashMap<String, HystrixMetricsPublisherThreadPool>();\n\n    /* package */ HystrixMetricsPublisherThreadPool getPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixMetricsPublisherThreadPool publisher = threadPoolPublishers.get(threadPoolKey.name());\n        if (publisher != null) {\n            return publisher;\n        }\n        // it doesn't exist so we need to create it\n        publisher = HystrixPlugins.getInstance().getMetricsPublisher().getMetricsPublisherForThreadPool(threadPoolKey, metrics, properties);\n        // attempt to store it (race other threads)\n        HystrixMetricsPublisherThreadPool existing = threadPoolPublishers.putIfAbsent(threadPoolKey.name(), publisher);\n        if (existing == null) {\n            // we won the thread-race to store the instance we created so initialize it\n            publisher.initialize();\n            // done registering, return instance that got cached\n            return publisher;\n        } else {\n            // we lost so return 'existing' and let the one we created be garbage collected\n            // without calling initialize() on it\n            return existing;\n        }\n    }\n\n    /**\n     * Get an instance of {@link HystrixMetricsPublisherCollapser} with the given factory {@link HystrixMetricsPublisher} implementation for each {@link HystrixCollapser} instance.\n     *\n     * @param collapserKey\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCollapser} implementation\n     * @param metrics\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCollapser} implementation\n     * @param properties\n     *            Pass-thru to {@link HystrixMetricsPublisher#getMetricsPublisherForCollapser} implementation\n     * @return {@link HystrixMetricsPublisherCollapser} instance\n     */\n    public static HystrixMetricsPublisherCollapser createOrRetrievePublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        return SINGLETON.getPublisherForCollapser(collapserKey, metrics, properties);\n    }\n\n    // String is CollapserKey.name() (we can't use CollapserKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private final ConcurrentHashMap<String, HystrixMetricsPublisherCollapser> collapserPublishers = new ConcurrentHashMap<String, HystrixMetricsPublisherCollapser>();\n\n    /* package */ HystrixMetricsPublisherCollapser getPublisherForCollapser(HystrixCollapserKey collapserKey, HystrixCollapserMetrics metrics, HystrixCollapserProperties properties) {\n        // attempt to retrieve from cache first\n        HystrixMetricsPublisherCollapser publisher = collapserPublishers.get(collapserKey.name());\n        if (publisher != null) {\n            return publisher;\n        }\n        // it doesn't exist so we need to create it\n        publisher = HystrixPlugins.getInstance().getMetricsPublisher().getMetricsPublisherForCollapser(collapserKey, metrics, properties);\n        // attempt to store it (race other threads)\n        HystrixMetricsPublisherCollapser existing = collapserPublishers.putIfAbsent(collapserKey.name(), publisher);\n        if (existing == null) {\n            // we won the thread-race to store the instance we created so initialize it\n            publisher.initialize();\n            // done registering, return instance that got cached\n            return publisher;\n        } else {\n            // we lost so return 'existing' and let the one we created be garbage collected\n            // without calling initialize() on it\n            return existing;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherThreadPool.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixThreadPool;\n\n/**\n * Metrics publisher for a {@link HystrixThreadPool} that will be constructed by an implementation of {@link HystrixMetricsPublisher}.\n * <p>\n * Instantiation of implementations of this interface should NOT allocate resources that require shutdown, register listeners or other such global state changes.\n * <p>\n * The <code>initialize()</code> method will be called once-and-only-once to indicate when this instance can register with external services, start publishing metrics etc.\n * <p>\n * Doing this logic in the constructor could result in memory leaks, double-publishing and other such behavior because this can be optimistically constructed more than once and \"extras\" discarded with\n * only one actually having <code>initialize()</code> called on it.\n */\npublic interface HystrixMetricsPublisherThreadPool {\n\n    // TODO should the arguments be given via initialize rather than constructor so people can't accidentally do it wrong?\n\n    public void initialize();\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherThreadPoolDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\n\n/**\n * Default implementation of {@link HystrixMetricsPublisherThreadPool} that does nothing.\n * <p>\n * See <a href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">Wiki docs</a> about plugins for more information.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixMetricsPublisherThreadPoolDefault implements HystrixMetricsPublisherThreadPool {\n\n    public HystrixMetricsPublisherThreadPoolDefault(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n        // do nothing by default\n    }\n\n    @Override\n    public void initialize() {\n        // do nothing by default\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/metrics/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Strategy definition for publishing metrics and default implementation.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.strategy.metrics;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Parent package of strategies and plugin management.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.strategy;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixDynamicProperties.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport java.util.ServiceLoader;\n\n/**\n * A hystrix plugin (SPI) for resolving dynamic configuration properties. This\n * SPI allows for varying configuration sources.\n * \n * The HystrixPlugin singleton will load only one implementation of this SPI\n * throught the {@link ServiceLoader} mechanism.\n * \n * @author agentgt\n *\n */\npublic interface HystrixDynamicProperties {\n    \n    /**\n     * Requests a property that may or may not actually exist.\n     * @param name property name, never <code>null</code>\n     * @param fallback default value, maybe <code>null</code>\n     * @return never <code>null</code>\n     */\n    public HystrixDynamicProperty<String> getString(String name, String fallback);\n    /**\n     * Requests a property that may or may not actually exist.\n     * @param name property name, never <code>null</code>\n     * @param fallback default value, maybe <code>null</code>\n     * @return never <code>null</code>\n     */\n    public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback);\n    /**\n     * Requests a property that may or may not actually exist.\n     * @param name property name, never <code>null</code>\n     * @param fallback default value, maybe <code>null</code>\n     * @return never <code>null</code>\n     */\n    public HystrixDynamicProperty<Long> getLong(String name, Long fallback);\n    /**\n     * Requests a property that may or may not actually exist.\n     * @param name property name\n     * @param fallback default value\n     * @return never <code>null</code>\n     */\n    public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback);\n    \n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class Util {\n        /**\n         * A convenience method to get a property by type (Class).\n         * @param properties never <code>null</code>\n         * @param name never <code>null</code>\n         * @param fallback maybe <code>null</code>\n         * @param type never <code>null</code>\n         * @return a dynamic property with type T.\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <T> HystrixDynamicProperty<T> getProperty(\n                HystrixDynamicProperties properties, String name, T fallback, Class<T> type) {\n            return (HystrixDynamicProperty<T>) doProperty(properties, name, fallback, type);\n        }\n        \n        private static HystrixDynamicProperty<?> doProperty(\n                HystrixDynamicProperties delegate, \n                String name, Object fallback, Class<?> type) {\n            if(type == String.class) {\n                return delegate.getString(name, (String) fallback);\n            }\n            else if (type == Integer.class) {\n                return delegate.getInteger(name, (Integer) fallback);\n            }\n            else if (type == Long.class) {\n                return delegate.getLong(name, (Long) fallback);\n            }\n            else if (type == Boolean.class) {\n                return delegate.getBoolean(name, (Boolean) fallback);\n            }\n            throw new IllegalStateException();\n        }\n    }\n    \n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixDynamicPropertiesSystemProperties.java",
    "content": "package com.netflix.hystrix.strategy.properties;\n\n/**\n * @ExcludeFromJavadoc\n * @author agent\n */\npublic final class HystrixDynamicPropertiesSystemProperties implements HystrixDynamicProperties {\n    \n    /**\n     * Only public for unit test purposes.\n     */\n    public HystrixDynamicPropertiesSystemProperties() {}\n    \n    private static class LazyHolder {\n        private static final HystrixDynamicPropertiesSystemProperties INSTANCE = new HystrixDynamicPropertiesSystemProperties();\n    }\n    \n    public static HystrixDynamicProperties getInstance() {\n        return LazyHolder.INSTANCE;\n    }\n    \n    //TODO probably should not be anonymous classes for GC reasons and possible jit method eliding.\n    @Override\n    public HystrixDynamicProperty<Integer> getInteger(final String name, final Integer fallback) {\n        return new HystrixDynamicProperty<Integer>() {\n            \n            @Override\n            public String getName() {\n                return name;\n            }\n            \n            @Override\n            public Integer get() {\n                return Integer.getInteger(name, fallback);\n            }\n            @Override\n            public void addCallback(Runnable callback) {\n            }\n        };\n    }\n\n    @Override\n    public HystrixDynamicProperty<String> getString(final String name, final String fallback) {\n        return new HystrixDynamicProperty<String>() {\n            \n            @Override\n            public String getName() {\n                return name;\n            }\n            \n            @Override\n            public String get() {\n                return System.getProperty(name, fallback);\n            }\n\n            @Override\n            public void addCallback(Runnable callback) {\n            }\n        };\n    }\n\n    @Override\n    public HystrixDynamicProperty<Long> getLong(final String name, final Long fallback) {\n        return new HystrixDynamicProperty<Long>() {\n            \n            @Override\n            public String getName() {\n                return name;\n            }\n            \n            @Override\n            public Long get() {\n                return Long.getLong(name, fallback);\n            }\n            \n            @Override\n            public void addCallback(Runnable callback) {\n            }\n        };\n    }\n\n    @Override\n    public HystrixDynamicProperty<Boolean> getBoolean(final String name, final Boolean fallback) {\n        return new HystrixDynamicProperty<Boolean>() {\n            \n            @Override\n            public String getName() {\n                return name;\n            }\n            @Override\n            public Boolean get() {\n                if (System.getProperty(name) == null) {\n                    return fallback;\n                }\n                return Boolean.getBoolean(name);\n            }\n            \n            @Override\n            public void addCallback(Runnable callback) {\n            }\n        };\n    }\n    \n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixDynamicProperty.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\n/**\n * Generic interface to represent a <b>dynamic</b> property value so Hystrix can consume\n * properties without being tied to any particular backing implementation.\n * \n * @author agentgt\n *\n * @param <T>\n *            Type of property value.\n * @see HystrixProperty\n * @see HystrixDynamicProperties\n */\npublic interface HystrixDynamicProperty<T> extends HystrixProperty<T>{\n    \n    public String getName();\n    \n    /**\n     * Register a callback to be run if the property is updated.\n     * Backing implementations may choose to do nothing.\n     * @param callback callback.\n     */\n    public void addCallback(Runnable callback);\n    \n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesChainedArchaiusProperty.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.config.PropertyWrapper;\n\n/**\n * Chained property allowing a chain of defaults using Archaius (https://github.com/Netflix/archaius) properties which is used by the default properties implementations.\n * <p>\n * Instead of just a single dynamic property with a default this allows a sequence of properties that fallback to the farthest down the chain with a value.\n * \n * TODO This should be replaced by a version in the Archaius library once available.\n * \n * @ExcludeFromJavadoc\n */\npublic abstract class HystrixPropertiesChainedArchaiusProperty {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixPropertiesChainedArchaiusProperty.class);\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static abstract class ChainLink<T> {\n\n        private final AtomicReference<ChainLink<T>> pReference;\n        private final ChainLink<T> next;\n        private final List<Runnable> callbacks;\n\n        /**\n         * @return String\n         */\n        public abstract String getName();\n\n        /**\n         * @return T\n         */\n        protected abstract T getValue();\n\n        /**\n         * @return Boolean\n         */\n        public abstract boolean isValueAcceptable();\n\n        /**\n         * No arg constructor - used for end node\n         */\n        public ChainLink() {\n            next = null;\n            pReference = new AtomicReference<ChainLink<T>>(this);\n            callbacks = new ArrayList<Runnable>();\n        }\n\n        /**\n         * @param nextProperty next property in the chain\n         */\n        public ChainLink(ChainLink<T> nextProperty) {\n            next = nextProperty;\n            pReference = new AtomicReference<ChainLink<T>>(next);\n            callbacks = new ArrayList<Runnable>();\n        }\n\n        protected void checkAndFlip() {\n            // in case this is the end node\n            if (next == null) {\n                pReference.set(this);\n                return;\n            }\n\n            if (this.isValueAcceptable()) {\n                logger.debug(\"Flipping property: {} to use its current value: {}\", getName(), getValue());\n                pReference.set(this);\n            } else {\n                logger.debug(\"Flipping property: {} to use NEXT property: {}\", getName(), next);\n                pReference.set(next);\n            }\n\n            for (Runnable r : callbacks) {\n                r.run();\n            }\n        }\n\n        /**\n         * @return T\n         */\n        public T get() {\n            if (pReference.get() == this) {\n                return this.getValue();\n            } else {\n                return pReference.get().get();\n            }\n        }\n\n        /**\n         * @param r callback to execut\n         */\n        public void addCallback(Runnable r) {\n            callbacks.add(r);\n        }\n\n        /**\n         * @return String\n         */\n        public String toString() {\n            return getName() + \" = \" + get();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class StringProperty extends ChainLink<String> {\n\n        private final DynamicStringProperty sProp;\n\n        public StringProperty(DynamicStringProperty sProperty) {\n            super();\n            sProp = sProperty;\n        }\n\n        public StringProperty(String name, DynamicStringProperty sProperty) {\n            this(name, new StringProperty(sProperty));\n        }\n\n        public StringProperty(String name, StringProperty next) {\n            this(new DynamicStringProperty(name, null), next);\n        }\n\n        public StringProperty(DynamicStringProperty sProperty, DynamicStringProperty next) {\n            this(sProperty, new StringProperty(next));\n        }\n\n        public StringProperty(DynamicStringProperty sProperty, StringProperty next) {\n            super(next); // setup next pointer\n\n            sProp = sProperty;\n            sProp.addCallback(new Runnable() {\n                @Override\n                public void run() {\n                    logger.debug(\"Property changed: '{} = {}'\", getName(), getValue());\n                    checkAndFlip();\n                }\n            });\n            checkAndFlip();\n        }\n\n        @Override\n        public boolean isValueAcceptable() {\n            return (sProp.get() != null);\n        }\n\n        @Override\n        protected String getValue() {\n            return sProp.get();\n        }\n\n        @Override\n        public String getName() {\n            return sProp.getName();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class IntegerProperty extends ChainLink<Integer> {\n\n        private final DynamicIntegerProperty sProp;\n\n        public IntegerProperty(DynamicIntegerProperty sProperty) {\n            super();\n            sProp = sProperty;\n        }\n\n        public IntegerProperty(String name, DynamicIntegerProperty sProperty) {\n            this(name, new IntegerProperty(sProperty));\n        }\n\n        public IntegerProperty(String name, IntegerProperty next) {\n            this(new DynamicIntegerProperty(name, null), next);\n        }\n\n        public IntegerProperty(DynamicIntegerProperty sProperty, DynamicIntegerProperty next) {\n            this(sProperty, new IntegerProperty(next));\n        }\n\n        public IntegerProperty(DynamicIntegerProperty sProperty, IntegerProperty next) {\n            super(next); // setup next pointer\n\n            sProp = sProperty;\n            sProp.addCallback(new Runnable() {\n                @Override\n                public void run() {\n                    logger.debug(\"Property changed: '{} = {}'\", getName(), getValue());\n                    checkAndFlip();\n                }\n            });\n            checkAndFlip();\n        }\n\n        @Override\n        public boolean isValueAcceptable() {\n            return (sProp.get() != null);\n        }\n\n        @Override\n        public Integer getValue() {\n            return sProp.get();\n        }\n\n        @Override\n        public String getName() {\n            return sProp.getName();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class BooleanProperty extends ChainLink<Boolean> {\n\n        private final DynamicBooleanProperty sProp;\n\n        public BooleanProperty(DynamicBooleanProperty sProperty) {\n            super();\n            sProp = sProperty;\n        }\n\n        public BooleanProperty(String name, DynamicBooleanProperty sProperty) {\n            this(name, new BooleanProperty(sProperty));\n        }\n\n        public BooleanProperty(String name, BooleanProperty next) {\n            this(new DynamicBooleanProperty(name, null), next);\n        }\n\n        public BooleanProperty(DynamicBooleanProperty sProperty, DynamicBooleanProperty next) {\n            this(sProperty, new BooleanProperty(next));\n        }\n\n        public BooleanProperty(DynamicBooleanProperty sProperty, BooleanProperty next) {\n            super(next); // setup next pointer\n\n            sProp = sProperty;\n            sProp.addCallback(new Runnable() {\n                @Override\n                public void run() {\n                    logger.debug(\"Property changed: '{} = {}'\", getName(), getValue());\n                    checkAndFlip();\n                }\n            });\n            checkAndFlip();\n        }\n\n        @Override\n        public boolean isValueAcceptable() {\n            return (sProp.getValue() != null);\n        }\n\n        @Override\n        public Boolean getValue() {\n            return sProp.get();\n        }\n\n        @Override\n        public String getName() {\n            return sProp.getName();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class DynamicBooleanProperty extends PropertyWrapper<Boolean> {\n        public DynamicBooleanProperty(String propName, Boolean defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        /**\n         * Get the current value from the underlying DynamicProperty\n         */\n        public Boolean get() {\n            return prop.getBoolean(defaultValue);\n        }\n\n        @Override\n        public Boolean getValue() {\n            return get();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class DynamicIntegerProperty extends PropertyWrapper<Integer> {\n        public DynamicIntegerProperty(String propName, Integer defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        /**\n         * Get the current value from the underlying DynamicProperty\n         */\n        public Integer get() {\n            return prop.getInteger(defaultValue);\n        }\n\n        @Override\n        public Integer getValue() {\n            return get();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class DynamicLongProperty extends PropertyWrapper<Long> {\n        public DynamicLongProperty(String propName, Long defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        /**\n         * Get the current value from the underlying DynamicProperty\n         */\n        public Long get() {\n            return prop.getLong(defaultValue);\n        }\n\n        @Override\n        public Long getValue() {\n            return get();\n        }\n    }\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    public static class DynamicStringProperty extends PropertyWrapper<String> {\n        public DynamicStringProperty(String propName, String defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        /**\n         * Get the current value from the underlying DynamicProperty\n         */\n        public String get() {\n            return prop.getString(defaultValue);\n        }\n\n        @Override\n        public String getValue() {\n            return get();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesChainedProperty.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Chained property allowing a chain of defaults properties which is uses the properties plugin.\n * <p>\n * Instead of just a single dynamic property with a default this allows a sequence of properties that fallback to the farthest down the chain with a value.\n * \n * TODO This should be replaced by a version in the Archaius library once available.\n * \n * @ExcludeFromJavadoc\n */\npublic abstract class HystrixPropertiesChainedProperty {\n    private static final Logger logger = LoggerFactory.getLogger(HystrixPropertiesChainedProperty.class);\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    private static abstract class ChainLink<T> {\n\n        private final AtomicReference<ChainLink<T>> pReference;\n        private final ChainLink<T> next;\n        private final List<Runnable> callbacks;\n\n        /**\n         * @return String\n         */\n        public abstract String getName();\n\n        /**\n         * @return T\n         */\n        protected abstract T getValue();\n\n        /**\n         * @return Boolean\n         */\n        public abstract boolean isValueAcceptable();\n\n        /**\n         * No arg constructor - used for end node\n         */\n        public ChainLink() {\n            next = null;\n            pReference = new AtomicReference<ChainLink<T>>(this);\n            callbacks = new ArrayList<Runnable>();\n        }\n\n        /**\n         * @param nextProperty next property in the chain\n         */\n        public ChainLink(ChainLink<T> nextProperty) {\n            next = nextProperty;\n            pReference = new AtomicReference<ChainLink<T>>(next);\n            callbacks = new ArrayList<Runnable>();\n        }\n\n        protected void checkAndFlip() {\n            // in case this is the end node\n            if (next == null) {\n                pReference.set(this);\n                return;\n            }\n\n            if (this.isValueAcceptable()) {\n                logger.debug(\"Flipping property: {} to use its current value: {}\", getName(), getValue());\n                pReference.set(this);\n            } else {\n                logger.debug(\"Flipping property: {} to use NEXT property: {}\", getName(), next);\n                pReference.set(next);\n            }\n\n            for (Runnable r : callbacks) {\n                r.run();\n            }\n        }\n\n        /**\n         * @return T\n         */\n        public T get() {\n            if (pReference.get() == this) {\n                return this.getValue();\n            } else {\n                return pReference.get().get();\n            }\n        }\n\n        /**\n         * @param r callback to execut\n         */\n        public void addCallback(Runnable r) {\n            callbacks.add(r);\n        }\n\n        /**\n         * @return String\n         */\n        public String toString() {\n            return getName() + \" = \" + get();\n        }\n    }\n    \n    public static abstract class ChainBuilder<T> {\n        \n        private ChainBuilder() {\n            super();        \n        }\n        \n        private List<HystrixDynamicProperty<T>> properties = \n                new ArrayList<HystrixDynamicProperty<T>>();\n        \n        \n        public ChainBuilder<T> add(HystrixDynamicProperty<T> property) {\n            properties.add(property);\n            return this;\n        }\n        \n        public ChainBuilder<T> add(String name, T defaultValue) {\n            properties.add(getDynamicProperty(name, defaultValue, getType()));\n            return this;\n        }\n        \n        public HystrixDynamicProperty<T> build() {\n            if (properties.size() < 1) throw new IllegalArgumentException();\n            if (properties.size() == 1) return properties.get(0);\n            List<HystrixDynamicProperty<T>> reversed = \n                    new ArrayList<HystrixDynamicProperty<T>>(properties);\n            Collections.reverse(reversed);\n            ChainProperty<T> current = null;\n            for (HystrixDynamicProperty<T> p : reversed) {\n                if (current == null) {\n                    current = new ChainProperty<T>(p);\n                }\n                else {\n                    current = new ChainProperty<T>(p, current);\n                }\n            }\n            \n            return new ChainHystrixProperty<T>(current);\n            \n        }\n        \n        protected abstract Class<T> getType();\n        \n    }\n\n    private static <T> ChainBuilder<T> forType(final Class<T> type) {\n        return new ChainBuilder<T>() {\n            @Override\n            protected Class<T> getType() {\n                return type;\n            }\n        };\n    }\n    \n    public static ChainBuilder<String> forString() {\n        return forType(String.class);\n    }\n    public static ChainBuilder<Integer> forInteger() {\n        return forType(Integer.class);\n    }\n    public static ChainBuilder<Boolean> forBoolean() {\n        return forType(Boolean.class);\n    }\n    public static ChainBuilder<Long> forLong() {\n        return forType(Long.class);\n    }    \n    \n    private static class ChainHystrixProperty<T> implements HystrixDynamicProperty<T> {\n        private final ChainProperty<T> property;\n        \n        public ChainHystrixProperty(ChainProperty<T> property) {\n            super();\n            this.property = property;\n        }\n        \n        @Override\n        public String getName() {\n            return property.getName();\n        }\n\n        @Override\n        public T get() {\n            return property.get();\n        }\n        \n        @Override\n        public void addCallback(Runnable callback) {\n            property.addCallback(callback);\n        }\n        \n    }\n    \n    private static class ChainProperty<T> extends ChainLink<T> {\n\n        private final HystrixDynamicProperty<T> sProp;\n\n        public ChainProperty(HystrixDynamicProperty<T> sProperty) {\n            super();\n            sProp = sProperty;\n        }\n\n\n        public ChainProperty(HystrixDynamicProperty<T> sProperty, ChainProperty<T> next) {\n            super(next); // setup next pointer\n\n            sProp = sProperty;\n            sProp.addCallback(new Runnable() {\n                @Override\n                public void run() {\n                    logger.debug(\"Property changed: '{} = {}'\", getName(), getValue());\n                    checkAndFlip();\n                }\n            });\n            checkAndFlip();\n        }\n\n        @Override\n        public boolean isValueAcceptable() {\n            return (sProp.get() != null);\n        }\n\n        @Override\n        protected T getValue() {\n            return sProp.get();\n        }\n\n        @Override\n        public String getName() {\n            return sProp.getName();\n        }\n        \n    }\n    \n    private static <T> HystrixDynamicProperty<T> \n        getDynamicProperty(String propName, T defaultValue, Class<T> type) {\n        HystrixDynamicProperties properties = HystrixPlugins.getInstance().getDynamicProperties();\n        HystrixDynamicProperty<T> p = \n                HystrixDynamicProperties.Util.getProperty(properties, propName, defaultValue, type);\n        return p;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesCollapserDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\n\n/**\n * Default implementation of {@link HystrixCollapserProperties} using Archaius (https://github.com/Netflix/archaius)\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesCollapserDefault extends HystrixCollapserProperties {\n\n    public HystrixPropertiesCollapserDefault(HystrixCollapserKey collapserKey, Setter builder) {\n        super(collapserKey, builder);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesCommandDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\n\n/**\n * Default implementation of {@link HystrixCommandProperties} using Archaius (https://github.com/Netflix/archaius)\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesCommandDefault extends HystrixCommandProperties {\n\n    public HystrixPropertiesCommandDefault(HystrixCommandKey key, Setter builder) {\n        super(key, builder);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesFactory.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Factory for retrieving properties implementations.\n * <p>\n * This uses given {@link HystrixPropertiesStrategy} implementations to construct Properties instances and caches each instance according to the cache key provided.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesFactory {\n\n    /**\n     * Clears all the defaults in the static property cache. This makes it possible for property defaults to not persist for\n     * an entire JVM lifetime.  May be invoked directly, and also gets invoked by <code>Hystrix.reset()</code>\n     */\n    public static void reset() {\n        commandProperties.clear();\n        threadPoolProperties.clear();\n        collapserProperties.clear();\n    }\n\n    // String is CommandKey.name() (we can't use CommandKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixCommandProperties> commandProperties = new ConcurrentHashMap<String, HystrixCommandProperties>();\n\n    /**\n     * Get an instance of {@link HystrixCommandProperties} with the given factory {@link HystrixPropertiesStrategy} implementation for each {@link HystrixCommand} instance.\n     * \n     * @param key\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getCommandProperties} implementation.\n     * @param builder\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getCommandProperties} implementation.\n     * @return {@link HystrixCommandProperties} instance\n     */\n    public static HystrixCommandProperties getCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder) {\n        HystrixPropertiesStrategy hystrixPropertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();\n        String cacheKey = hystrixPropertiesStrategy.getCommandPropertiesCacheKey(key, builder);\n        if (cacheKey != null) {\n            HystrixCommandProperties properties = commandProperties.get(cacheKey);\n            if (properties != null) {\n                return properties;\n            } else {\n                if (builder == null) {\n                    builder = HystrixCommandProperties.Setter();\n                }\n                // create new instance\n                properties = hystrixPropertiesStrategy.getCommandProperties(key, builder);\n                // cache and return\n                HystrixCommandProperties existing = commandProperties.putIfAbsent(cacheKey, properties);\n                if (existing == null) {\n                    return properties;\n                } else {\n                    return existing;\n                }\n            }\n        } else {\n            // no cacheKey so we generate it with caching\n            return hystrixPropertiesStrategy.getCommandProperties(key, builder);\n        }\n    }\n\n    // String is ThreadPoolKey.name() (we can't use ThreadPoolKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixThreadPoolProperties> threadPoolProperties = new ConcurrentHashMap<String, HystrixThreadPoolProperties>();\n\n    /**\n     * Get an instance of {@link HystrixThreadPoolProperties} with the given factory {@link HystrixPropertiesStrategy} implementation for each {@link HystrixThreadPool} instance.\n     * \n     * @param key\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getThreadPoolProperties} implementation.\n     * @param builder\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getThreadPoolProperties} implementation.\n     * @return {@link HystrixThreadPoolProperties} instance\n     */\n    public static HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey key, HystrixThreadPoolProperties.Setter builder) {\n        HystrixPropertiesStrategy hystrixPropertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();\n        String cacheKey = hystrixPropertiesStrategy.getThreadPoolPropertiesCacheKey(key, builder);\n        if (cacheKey != null) {\n            HystrixThreadPoolProperties properties = threadPoolProperties.get(cacheKey);\n            if (properties != null) {\n                return properties;\n            } else {\n                if (builder == null) {\n                    builder = HystrixThreadPoolProperties.Setter();\n                }\n                // create new instance\n                properties = hystrixPropertiesStrategy.getThreadPoolProperties(key, builder);\n                // cache and return\n                HystrixThreadPoolProperties existing = threadPoolProperties.putIfAbsent(cacheKey, properties);\n                if (existing == null) {\n                    return properties;\n                } else {\n                    return existing;\n                }\n            }\n        } else {\n            // no cacheKey so we generate it with caching\n            return hystrixPropertiesStrategy.getThreadPoolProperties(key, builder);\n        }\n    }\n\n    // String is CollapserKey.name() (we can't use CollapserKey directly as we can't guarantee it implements hashcode/equals correctly)\n    private static final ConcurrentHashMap<String, HystrixCollapserProperties> collapserProperties = new ConcurrentHashMap<String, HystrixCollapserProperties>();\n\n    /**\n     * Get an instance of {@link HystrixCollapserProperties} with the given factory {@link HystrixPropertiesStrategy} implementation for each {@link HystrixCollapserKey} instance.\n     * \n     * @param key\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getCollapserProperties} implementation.\n     * @param builder\n     *            Pass-thru to {@link HystrixPropertiesStrategy#getCollapserProperties} implementation.\n     * @return {@link HystrixCollapserProperties} instance\n     */\n    public static HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey key, HystrixCollapserProperties.Setter builder) {\n        HystrixPropertiesStrategy hystrixPropertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();\n        String cacheKey = hystrixPropertiesStrategy.getCollapserPropertiesCacheKey(key, builder);\n        if (cacheKey != null) {\n            HystrixCollapserProperties properties = collapserProperties.get(cacheKey);\n            if (properties != null) {\n                return properties;\n            } else {\n                if (builder == null) {\n                    builder = HystrixCollapserProperties.Setter();\n                }\n                // create new instance\n                properties = hystrixPropertiesStrategy.getCollapserProperties(key, builder);\n                // cache and return\n                HystrixCollapserProperties existing = collapserProperties.putIfAbsent(cacheKey, properties);\n                if (existing == null) {\n                    return properties;\n                } else {\n                    return existing;\n                }\n            }\n        } else {\n            // no cacheKey so we generate it with caching\n            return hystrixPropertiesStrategy.getCollapserProperties(key, builder);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategy.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPool;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.HystrixTimerThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\n\n/**\n * Abstract class with default implementations of factory methods for properties used by various components of Hystrix.\n * <p>\n * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a\n * href=\"https://github.com/Netflix/Hystrix/wiki/Plugins\">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.\n */\npublic abstract class HystrixPropertiesStrategy {\n\n    /**\n     * Construct an implementation of {@link HystrixCommandProperties} for {@link HystrixCommand} instances with {@link HystrixCommandKey}.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Constructs instance of {@link HystrixPropertiesCommandDefault}.\n     * \n     * @param commandKey\n     *            {@link HystrixCommandKey} representing the name or type of {@link HystrixCommand}\n     * @param builder\n     *            {@link com.netflix.hystrix.HystrixCommandProperties.Setter} with default overrides as injected from the {@link HystrixCommand} implementation.\n     *            <p>\n     *            The builder will return NULL for each value if no override was provided.\n     * @return Implementation of {@link HystrixCommandProperties}\n     */\n    public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {\n        return new HystrixPropertiesCommandDefault(commandKey, builder);\n    }\n\n    /**\n     * Cache key used for caching the retrieval of {@link HystrixCommandProperties} implementations.\n     * <p>\n     * Typically this would return <code>HystrixCommandKey.name()</code> but can be done differently if required.\n     * <p>\n     * For example, null can be returned which would cause it to not cache and invoke {@link #getCommandProperties} for each {@link HystrixCommand} instantiation (not recommended).\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Returns {@link HystrixCommandKey#name()}\n     * \n     * @param commandKey command key used in determining command's cache key\n     * @param builder builder for {@link HystrixCommandProperties} used in determining command's cache key\n     * @return String value to be used as the cache key of a {@link HystrixCommandProperties} implementation.\n     */\n    public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {\n        return commandKey.name();\n    }\n\n    /**\n     * Construct an implementation of {@link HystrixThreadPoolProperties} for {@link HystrixThreadPool} instances with {@link HystrixThreadPoolKey}.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Constructs instance of {@link HystrixPropertiesThreadPoolDefault}.\n     * \n     * @param threadPoolKey\n     *            {@link HystrixThreadPoolKey} representing the name or type of {@link HystrixThreadPool}\n     * @param builder\n     *            {@link com.netflix.hystrix.HystrixThreadPoolProperties.Setter} with default overrides as injected via {@link HystrixCommand} to the {@link HystrixThreadPool} implementation.\n     *            <p>\n     *            The builder will return NULL for each value if no override was provided.\n     * \n     * @return Implementation of {@link HystrixThreadPoolProperties}\n     */\n    public HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) {\n        return new HystrixPropertiesThreadPoolDefault(threadPoolKey, builder);\n    }\n\n    /**\n     * Cache key used for caching the retrieval of {@link HystrixThreadPoolProperties} implementations.\n     * <p>\n     * Typically this would return <code>HystrixThreadPoolKey.name()</code> but can be done differently if required.\n     * <p>\n     * For example, null can be returned which would cause it to not cache and invoke {@link #getThreadPoolProperties} for each {@link HystrixThreadPool} instantiation (not recommended).\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Returns {@link HystrixThreadPoolKey#name()}\n     *\n     * @param threadPoolKey thread pool key used in determining thread pool's cache key\n     * @param builder builder for {@link HystrixThreadPoolProperties} used in determining thread pool's cache key\n     * @return String value to be used as the cache key of a {@link HystrixThreadPoolProperties} implementation.\n     */\n    public String getThreadPoolPropertiesCacheKey(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) {\n        return threadPoolKey.name();\n    }\n\n    /**\n     * Construct an implementation of {@link HystrixCollapserProperties} for {@link HystrixCollapser} instances with {@link HystrixCollapserKey}.\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Constructs instance of {@link HystrixPropertiesCollapserDefault}.\n     * \n     * @param collapserKey\n     *            {@link HystrixCollapserKey} representing the name or type of {@link HystrixCollapser}\n     * @param builder\n     *            {@link com.netflix.hystrix.HystrixCollapserProperties.Setter} with default overrides as injected to the {@link HystrixCollapser} implementation.\n     *            <p>\n     *            The builder will return NULL for each value if no override was provided.\n     * \n     * @return Implementation of {@link HystrixCollapserProperties}\n     */\n    public HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) {\n        return new HystrixPropertiesCollapserDefault(collapserKey, builder);\n    }\n\n    /**\n     * Cache key used for caching the retrieval of {@link HystrixCollapserProperties} implementations.\n     * <p>\n     * Typically this would return <code>HystrixCollapserKey.name()</code> but can be done differently if required.\n     * <p>\n     * For example, null can be returned which would cause it to not cache and invoke {@link #getCollapserProperties} for each {@link HystrixCollapser} instantiation (not recommended).\n     * <p>\n     * <b>Default Implementation</b>\n     * <p>\n     * Returns {@link HystrixCollapserKey#name()}\n     *\n     * @param collapserKey collapser key used in determining collapser's cache key\n     * @param builder builder for {@link HystrixCollapserProperties} used in determining collapser's cache key\n     * @return String value to be used as the cache key of a {@link HystrixCollapserProperties} implementation.\n     */\n    public String getCollapserPropertiesCacheKey(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) {\n        return collapserKey.name();\n    }\n\n    /**\n     * Construct an implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties} for configuration of the timer thread pool\n     * that handles timeouts and collapser logic.\n     * <p>\n     * Constructs instance of {@link HystrixPropertiesTimerThreadPoolDefault}.\n     *\n     *\n     * @return Implementation of {@link com.netflix.hystrix.HystrixTimerThreadPoolProperties}\n     */\n    public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() {\n        return new HystrixPropertiesTimerThreadPoolDefault();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesStrategyDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\n/**\n * Default implementation of {@link HystrixPropertiesStrategy}.\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesStrategyDefault extends HystrixPropertiesStrategy {\n\n    private final static HystrixPropertiesStrategyDefault INSTANCE = new HystrixPropertiesStrategyDefault();\n\n    private HystrixPropertiesStrategyDefault() {\n    }\n\n    public static HystrixPropertiesStrategy getInstance() {\n        return INSTANCE;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesThreadPoolDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\n\n/**\n * Default implementation of {@link HystrixThreadPoolProperties} using Archaius (https://github.com/Netflix/archaius)\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesThreadPoolDefault extends HystrixThreadPoolProperties {\n\n    protected HystrixPropertiesThreadPoolDefault(HystrixThreadPoolKey key, Setter builder) {\n        super(key, builder);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesTimerThreadPoolDefault.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.HystrixTimerThreadPoolProperties;\n\n/**\n * Default implementation of {@link HystrixTimerThreadPoolProperties} using Archaius (https://github.com/Netflix/archaius)\n * \n * @ExcludeFromJavadoc\n */\npublic class HystrixPropertiesTimerThreadPoolDefault extends HystrixTimerThreadPoolProperties {\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/HystrixProperty.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicBooleanProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicIntegerProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicLongProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicStringProperty;\n\n/**\n * Generic interface to represent a property value so Hystrix can consume properties without being tied to any particular backing implementation.\n * \n * @param <T>\n *            Type of property value\n */\npublic interface HystrixProperty<T> {\n\n    public T get();\n\n    /**\n     * Helper methods for wrapping static values and dynamic Archaius (https://github.com/Netflix/archaius) properties in the {@link HystrixProperty} interface.\n     */\n    public static class Factory {\n\n        public static <T> HystrixProperty<T> asProperty(final T value) {\n            return new HystrixProperty<T>() {\n\n                @Override\n                public T get() {\n                    return value;\n                }\n\n            };\n        }\n\n        /**\n         * @ExcludeFromJavadoc\n         */\n        public static HystrixProperty<Integer> asProperty(final DynamicIntegerProperty value) {\n            return new HystrixProperty<Integer>() {\n\n                @Override\n                public Integer get() {\n                    return value.get();\n                }\n\n            };\n        }\n\n        /**\n         * @ExcludeFromJavadoc\n         */\n        public static HystrixProperty<Long> asProperty(final DynamicLongProperty value) {\n            return new HystrixProperty<Long>() {\n\n                @Override\n                public Long get() {\n                    return value.get();\n                }\n\n            };\n        }\n\n        /**\n         * @ExcludeFromJavadoc\n         */\n        public static HystrixProperty<String> asProperty(final DynamicStringProperty value) {\n            return new HystrixProperty<String>() {\n\n                @Override\n                public String get() {\n                    return value.get();\n                }\n\n            };\n        }\n\n        /**\n         * @ExcludeFromJavadoc\n         */\n        public static HystrixProperty<Boolean> asProperty(final DynamicBooleanProperty value) {\n            return new HystrixProperty<Boolean>() {\n\n                @Override\n                public Boolean get() {\n                    return value.get();\n                }\n\n            };\n        }\n\n        /**\n         * When retrieved this will return the value from the given {@link HystrixProperty} or if that returns null then return the <code>defaultValue</code>.\n         * \n         * @param value\n         *            {@link HystrixProperty} of property value that can return null (meaning no value)\n         * @param defaultValue\n         *            value to be returned if value returns null\n         * @return value or defaultValue if value returns null\n         */\n        public static <T> HystrixProperty<T> asProperty(final HystrixProperty<T> value, final T defaultValue) {\n            return new HystrixProperty<T>() {\n\n                @Override\n                public T get() {\n                    T v = value.get();\n                    if (v == null) {\n                        return defaultValue;\n                    } else {\n                        return v;\n                    }\n                }\n\n            };\n        }\n\n        /**\n         * When retrieved this will iterate over the contained {@link HystrixProperty} instances until a non-null value is found and return that.\n         * \n         * @param values properties to iterate over\n         * @return first non-null value or null if none found\n         */\n        public static <T> HystrixProperty<T> asProperty(final HystrixProperty<T>... values) {\n            return new HystrixProperty<T>() {\n\n                @Override\n                public T get() {\n                    for (HystrixProperty<T> v : values) {\n                        // return the first one that doesn't return null\n                        if (v.get() != null) {\n                            return v.get();\n                        }\n                    }\n                    return null;\n                }\n\n            };\n        }\n\n        /**\n         * @ExcludeFromJavadoc\n         */\n        public static <T> HystrixProperty<T> asProperty(final HystrixPropertiesChainedArchaiusProperty.ChainLink<T> chainedProperty) {\n            return new HystrixProperty<T>() {\n\n                @Override\n                public T get() {\n                    return chainedProperty.get();\n                }\n\n            };\n        }\n\n        public static <T> HystrixProperty<T> nullProperty() {\n            return new HystrixProperty<T>() {\n\n                @Override\n                public T get() {\n                    return null;\n                }\n\n            };\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/archaius/HystrixDynamicPropertiesArchaius.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties.archaius;\n\nimport com.netflix.config.PropertyWrapper;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperties;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperty;\n\n/**\n * This class should not be imported from any class in core or else Archaius will be loaded.\n * @author agentgt\n * @ExcludeFromJavadoc\n */\n/* package */ public class HystrixDynamicPropertiesArchaius implements HystrixDynamicProperties {\n\n    /**\n     * @ExcludeFromJavadoc\n     */\n    @Override\n    public HystrixDynamicProperty<String> getString(String name, String fallback) {\n        return new StringDynamicProperty(name, fallback);\n    }\n    /**\n     * @ExcludeFromJavadoc\n     */\n    @Override\n    public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback) {\n        return new IntegerDynamicProperty(name, fallback);\n    }\n    /**\n     * @ExcludeFromJavadoc\n     */\n    @Override\n    public HystrixDynamicProperty<Long> getLong(String name, Long fallback) {\n        return new LongDynamicProperty(name, fallback);\n    }\n    /**\n     * @ExcludeFromJavadoc\n     */\n    @Override\n    public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback) {\n        return new BooleanDynamicProperty(name, fallback);\n    }\n    \n    private abstract static class ArchaiusDynamicProperty<T> \n        extends PropertyWrapper<T> implements HystrixDynamicProperty<T> {\n\n        protected ArchaiusDynamicProperty(String propName, T defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        @Override\n        public T get() {\n            return getValue();\n        }\n    }\n    \n    private static class StringDynamicProperty extends ArchaiusDynamicProperty<String> {\n        protected StringDynamicProperty(String propName, String defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        @Override\n        public String getValue() {\n            return prop.getString(defaultValue);\n        }\n    }\n\n    private static class IntegerDynamicProperty extends ArchaiusDynamicProperty<Integer> {\n        protected IntegerDynamicProperty(String propName, Integer defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        @Override\n        public Integer getValue() {\n            return prop.getInteger(defaultValue);\n        }\n    }\n    \n    private static class LongDynamicProperty extends ArchaiusDynamicProperty<Long> {\n        protected LongDynamicProperty(String propName, Long defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        @Override\n        public Long getValue() {\n            return prop.getLong(defaultValue);\n        }\n    }\n    \n    private static class BooleanDynamicProperty extends ArchaiusDynamicProperty<Boolean> {\n        protected BooleanDynamicProperty(String propName, Boolean defaultValue) {\n            super(propName, defaultValue);\n        }\n\n        @Override\n        public Boolean getValue() {\n            return prop.getBoolean(defaultValue);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/strategy/properties/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Strategy definition for properties and configuration and default implementation.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.strategy.properties;"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/ExceptionThreadingUtility.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\n@Deprecated\npublic class ExceptionThreadingUtility {\n\n    @Deprecated //this functionality is no longer supported\n    public static void attachCallingThreadStack(Throwable e) {\n        //no-op now\n    }\n\n    @Deprecated //this functionality is no longer supported\n    public static void assignCallingThread(Thread callingThread) {\n        //no-op now\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/Exceptions.java",
    "content": "package com.netflix.hystrix.util;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class Exceptions {\n    private Exceptions() {\n    }\n\n    /**\n     * Throws the argument, return-type is RuntimeException so the caller can use a throw statement break out of the method\n     */\n    public static RuntimeException sneakyThrow(Throwable t) {\n        return Exceptions.<RuntimeException>doThrow(t);\n    }\n\n    private static <T extends Throwable> T doThrow(Throwable ex) throws T {\n        throw (T) ex;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixRollingNumber.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.atomic.AtomicReferenceArray;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\n\n/**\n * A number which can be used to track counters (increment) or set values over time.\n * <p>\n * It is \"rolling\" in the sense that a 'timeInMilliseconds' is given that you want to track (such as 10 seconds) and then that is broken into buckets (defaults to 10) so that the 10 second window\n * doesn't empty out and restart every 10 seconds, but instead every 1 second you have a new bucket added and one dropped so that 9 of the buckets remain and only the newest starts from scratch.\n * <p>\n * This is done so that the statistics are gathered over a rolling 10 second window with data being added/dropped in 1 second intervals (or whatever granularity is defined by the arguments) rather\n * than each 10 second window starting at 0 again.\n * <p>\n * Performance-wise this class is optimized for writes, not reads. This is done because it expects far higher write volume (thousands/second) than reads (a few per second).\n * <p>\n * For example, on each read to getSum/getCount it will iterate buckets to sum the data so that on writes we don't need to maintain the overall sum and pay the synchronization cost at each write to\n * ensure the sum is up-to-date when the read can easily iterate each bucket to get the sum when it needs it.\n * <p>\n * See UnitTest for usage and expected behavior examples.\n * \n * @ThreadSafe\n */\npublic class HystrixRollingNumber {\n\n    private static final Time ACTUAL_TIME = new ActualTime();\n    private final Time time;\n    final int timeInMilliseconds;\n    final int numberOfBuckets;\n    final int bucketSizeInMillseconds;\n\n    final BucketCircularArray buckets;\n    private final CumulativeSum cumulativeSum = new CumulativeSum();\n\n    /**\n     * Construct a counter, with configurable properties for how many buckets, and how long of an interval to track\n     * @param timeInMilliseconds length of time to report metrics over\n     * @param numberOfBuckets number of buckets to use\n     *\n     * @deprecated Please use {@link HystrixRollingNumber(int, int) instead}.  These values are no longer allowed to\n     * be updated at runtime.\n     */\n    @Deprecated\n    public HystrixRollingNumber(HystrixProperty<Integer> timeInMilliseconds, HystrixProperty<Integer> numberOfBuckets) {\n        this(timeInMilliseconds.get(), numberOfBuckets.get());\n    }\n\n    public HystrixRollingNumber(int timeInMilliseconds, int numberOfBuckets) {\n        this(ACTUAL_TIME, timeInMilliseconds, numberOfBuckets);\n    }\n\n    /* package for testing */ HystrixRollingNumber(Time time, int timeInMilliseconds, int numberOfBuckets) {\n        this.time = time;\n        this.timeInMilliseconds = timeInMilliseconds;\n        this.numberOfBuckets = numberOfBuckets;\n\n        if (timeInMilliseconds % numberOfBuckets != 0) {\n            throw new IllegalArgumentException(\"The timeInMilliseconds must divide equally into numberOfBuckets. For example 1000/10 is ok, 1000/11 is not.\");\n        }\n        this.bucketSizeInMillseconds = timeInMilliseconds / numberOfBuckets;\n\n        buckets = new BucketCircularArray(numberOfBuckets);\n    }\n\n    /**\n     * Increment the counter in the current bucket by one for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which counter to increment\n     */\n    public void increment(HystrixRollingNumberEvent type) {\n        getCurrentBucket().getAdder(type).increment();\n    }\n\n    /**\n     * Add to the counter in the current bucket for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which counter to add to\n     * @param value\n     *            long value to be added to the current bucket\n     */\n    public void add(HystrixRollingNumberEvent type, long value) {\n        getCurrentBucket().getAdder(type).add(value);\n    }\n\n    /**\n     * Update a value and retain the max value.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"max updater\" type <code>HystrixRollingNumberEvent.isMaxUpdater() == true</code>.\n     * \n     * @param type  HystrixRollingNumberEvent defining which counter to retrieve values from\n     * @param value long value to be given to the max updater\n     */\n    public void updateRollingMax(HystrixRollingNumberEvent type, long value) {\n        getCurrentBucket().getMaxUpdater(type).update(value);\n    }\n\n    /**\n     * Force a reset of all rolling counters (clear all buckets) so that statistics start being gathered from scratch.\n     * <p>\n     * This does NOT reset the CumulativeSum values.\n     */\n    public void reset() {\n        // if we are resetting, that means the lastBucket won't have a chance to be captured in CumulativeSum, so let's do it here\n        Bucket lastBucket = buckets.peekLast();\n        if (lastBucket != null) {\n            cumulativeSum.addBucket(lastBucket);\n        }\n\n        // clear buckets so we start over again\n        buckets.clear();\n    }\n\n    /**\n     * Get the cumulative sum of all buckets ever since the JVM started without rolling for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * See {@link #getRollingSum(HystrixRollingNumberEvent)} for the rolling sum.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type HystrixRollingNumberEvent defining which counter to retrieve values from\n     * @return cumulative sum of all increments and adds for the given {@link HystrixRollingNumberEvent} counter type\n     */\n    public long getCumulativeSum(HystrixRollingNumberEvent type) {\n        // this isn't 100% atomic since multiple threads can be affecting latestBucket & cumulativeSum independently\n        // but that's okay since the count is always a moving target and we're accepting a \"point in time\" best attempt\n        // we are however putting 'getValueOfLatestBucket' first since it can have side-affects on cumulativeSum whereas the inverse is not true\n        return getValueOfLatestBucket(type) + cumulativeSum.get(type);\n    }\n\n    /**\n     * Get the sum of all buckets in the rolling counter for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which counter to retrieve values from\n     * @return\n     *         value from the given {@link HystrixRollingNumberEvent} counter type\n     */\n    public long getRollingSum(HystrixRollingNumberEvent type) {\n        Bucket lastBucket = getCurrentBucket();\n        if (lastBucket == null)\n            return 0;\n\n        long sum = 0;\n        for (Bucket b : buckets) {\n            sum += b.getAdder(type).sum();\n        }\n        return sum;\n    }\n\n    /**\n     * Get the value of the latest (current) bucket in the rolling counter for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which counter to retrieve value from\n     * @return\n     *         value from latest bucket for given {@link HystrixRollingNumberEvent} counter type\n     */\n    public long getValueOfLatestBucket(HystrixRollingNumberEvent type) {\n        Bucket lastBucket = getCurrentBucket();\n        if (lastBucket == null)\n            return 0;\n        // we have bucket data so we'll return the lastBucket\n        return lastBucket.get(type);\n    }\n\n    /**\n     * Get an array of values for all buckets in the rolling counter for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * Index 0 is the oldest bucket.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"counter\" type <code>HystrixRollingNumberEvent.isCounter() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which counter to retrieve values from\n     * @return array of values from each of the rolling buckets for given {@link HystrixRollingNumberEvent} counter type\n     */\n    public long[] getValues(HystrixRollingNumberEvent type) {\n        Bucket lastBucket = getCurrentBucket();\n        if (lastBucket == null)\n            return new long[0];\n\n        // get buckets as an array (which is a copy of the current state at this point in time)\n        Bucket[] bucketArray = buckets.getArray();\n\n        // we have bucket data so we'll return an array of values for all buckets\n        long values[] = new long[bucketArray.length];\n        int i = 0;\n        for (Bucket bucket : bucketArray) {\n            if (type.isCounter()) {\n                values[i++] = bucket.getAdder(type).sum();\n            } else if (type.isMaxUpdater()) {\n                values[i++] = bucket.getMaxUpdater(type).max();\n            }\n        }\n        return values;\n    }\n\n    /**\n     * Get the max value of values in all buckets for the given {@link HystrixRollingNumberEvent} type.\n     * <p>\n     * The {@link HystrixRollingNumberEvent} must be a \"max updater\" type <code>HystrixRollingNumberEvent.isMaxUpdater() == true</code>.\n     * \n     * @param type\n     *            HystrixRollingNumberEvent defining which \"max updater\" to retrieve values from\n     * @return max value for given {@link HystrixRollingNumberEvent} type during rolling window\n     */\n    public long getRollingMaxValue(HystrixRollingNumberEvent type) {\n        long values[] = getValues(type);\n        if (values.length == 0) {\n            return 0;\n        } else {\n            Arrays.sort(values);\n            return values[values.length - 1];\n        }\n    }\n\n    private ReentrantLock newBucketLock = new ReentrantLock();\n\n    /* package for testing */Bucket getCurrentBucket() {\n        long currentTime = time.getCurrentTimeInMillis();\n\n        /* a shortcut to try and get the most common result of immediately finding the current bucket */\n\n        /**\n         * Retrieve the latest bucket if the given time is BEFORE the end of the bucket window, otherwise it returns NULL.\n         * \n         * NOTE: This is thread-safe because it's accessing 'buckets' which is a LinkedBlockingDeque\n         */\n        Bucket currentBucket = buckets.peekLast();\n        if (currentBucket != null && currentTime < currentBucket.windowStart + this.bucketSizeInMillseconds) {\n            // if we're within the bucket 'window of time' return the current one\n            // NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,\n            // we'll just use the latest as long as we're not AFTER the window\n            return currentBucket;\n        }\n\n        /* if we didn't find the current bucket above, then we have to create one */\n\n        /**\n         * The following needs to be synchronized/locked even with a synchronized/thread-safe data structure such as LinkedBlockingDeque because\n         * the logic involves multiple steps to check existence, create an object then insert the object. The 'check' or 'insertion' themselves\n         * are thread-safe by themselves but not the aggregate algorithm, thus we put this entire block of logic inside synchronized.\n         * \n         * I am using a tryLock if/then (http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/Lock.html#tryLock())\n         * so that a single thread will get the lock and as soon as one thread gets the lock all others will go the 'else' block\n         * and just return the currentBucket until the newBucket is created. This should allow the throughput to be far higher\n         * and only slow down 1 thread instead of blocking all of them in each cycle of creating a new bucket based on some testing\n         * (and it makes sense that it should as well).\n         * \n         * This means the timing won't be exact to the millisecond as to what data ends up in a bucket, but that's acceptable.\n         * It's not critical to have exact precision to the millisecond, as long as it's rolling, if we can instead reduce the impact synchronization.\n         * \n         * More importantly though it means that the 'if' block within the lock needs to be careful about what it changes that can still\n         * be accessed concurrently in the 'else' block since we're not completely synchronizing access.\n         * \n         * For example, we can't have a multi-step process to add a bucket, remove a bucket, then update the sum since the 'else' block of code\n         * can retrieve the sum while this is all happening. The trade-off is that we don't maintain the rolling sum and let readers just iterate\n         * bucket to calculate the sum themselves. This is an example of favoring write-performance instead of read-performance and how the tryLock\n         * versus a synchronized block needs to be accommodated.\n         */\n        if (newBucketLock.tryLock()) {\n            try {\n                if (buckets.peekLast() == null) {\n                    // the list is empty so create the first bucket\n                    Bucket newBucket = new Bucket(currentTime);\n                    buckets.addLast(newBucket);\n                    return newBucket;\n                } else {\n                    // We go into a loop so that it will create as many buckets as needed to catch up to the current time\n                    // as we want the buckets complete even if we don't have transactions during a period of time.\n                    for (int i = 0; i < numberOfBuckets; i++) {\n                        // we have at least 1 bucket so retrieve it\n                        Bucket lastBucket = buckets.peekLast();\n                        if (currentTime < lastBucket.windowStart + this.bucketSizeInMillseconds) {\n                            // if we're within the bucket 'window of time' return the current one\n                            // NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,\n                            // we'll just use the latest as long as we're not AFTER the window\n                            return lastBucket;\n                        } else if (currentTime - (lastBucket.windowStart + this.bucketSizeInMillseconds) > timeInMilliseconds) {\n                            // the time passed is greater than the entire rolling counter so we want to clear it all and start from scratch\n                            reset();\n                            // recursively call getCurrentBucket which will create a new bucket and return it\n                            return getCurrentBucket();\n                        } else { // we're past the window so we need to create a new bucket\n                            // create a new bucket and add it as the new 'last'\n                            buckets.addLast(new Bucket(lastBucket.windowStart + this.bucketSizeInMillseconds));\n                            // add the lastBucket values to the cumulativeSum\n                            cumulativeSum.addBucket(lastBucket);\n                        }\n                    }\n                    // we have finished the for-loop and created all of the buckets, so return the lastBucket now\n                    return buckets.peekLast();\n                }\n            } finally {\n                newBucketLock.unlock();\n            }\n        } else {\n            currentBucket = buckets.peekLast();\n            if (currentBucket != null) {\n                // we didn't get the lock so just return the latest bucket while another thread creates the next one\n                return currentBucket;\n            } else {\n                // the rare scenario where multiple threads raced to create the very first bucket\n                // wait slightly and then use recursion while the other thread finishes creating a bucket\n                try {\n                    Thread.sleep(5);\n                } catch (Exception e) {\n                    // ignore\n                }\n                return getCurrentBucket();\n            }\n        }\n    }\n\n    /* package */static interface Time {\n        public long getCurrentTimeInMillis();\n    }\n\n    private static class ActualTime implements Time {\n\n        @Override\n        public long getCurrentTimeInMillis() {\n            return System.currentTimeMillis();\n        }\n\n    }\n\n    /**\n     * Counters for a given 'bucket' of time.\n     */\n    /* package */static class Bucket {\n        final long windowStart;\n        final LongAdder[] adderForCounterType;\n        final LongMaxUpdater[] updaterForCounterType;\n\n        Bucket(long startTime) {\n            this.windowStart = startTime;\n\n            /*\n             * We support both LongAdder and LongMaxUpdater in a bucket but don't want the memory allocation\n             * of all types for each so we only allocate the objects if the HystrixRollingNumberEvent matches\n             * the correct type - though we still have the allocation of empty arrays to the given length\n             * as we want to keep using the type.ordinal() value for fast random access.\n             */\n\n            // initialize the array of LongAdders\n            adderForCounterType = new LongAdder[HystrixRollingNumberEvent.values().length];\n            for (HystrixRollingNumberEvent type : HystrixRollingNumberEvent.values()) {\n                if (type.isCounter()) {\n                    adderForCounterType[type.ordinal()] = new LongAdder();\n                }\n            }\n\n            updaterForCounterType = new LongMaxUpdater[HystrixRollingNumberEvent.values().length];\n            for (HystrixRollingNumberEvent type : HystrixRollingNumberEvent.values()) {\n                if (type.isMaxUpdater()) {\n                    updaterForCounterType[type.ordinal()] = new LongMaxUpdater();\n                    // initialize to 0 otherwise it is Long.MIN_VALUE\n                    updaterForCounterType[type.ordinal()].update(0);\n                }\n            }\n        }\n\n        long get(HystrixRollingNumberEvent type) {\n            if (type.isCounter()) {\n                return adderForCounterType[type.ordinal()].sum();\n            }\n            if (type.isMaxUpdater()) {\n                return updaterForCounterType[type.ordinal()].max();\n            }\n            throw new IllegalStateException(\"Unknown type of event: \" + type.name());\n        }\n\n        LongAdder getAdder(HystrixRollingNumberEvent type) {\n            if (!type.isCounter()) {\n                throw new IllegalStateException(\"Type is not a Counter: \" + type.name());\n            }\n            return adderForCounterType[type.ordinal()];\n        }\n\n        LongMaxUpdater getMaxUpdater(HystrixRollingNumberEvent type) {\n            if (!type.isMaxUpdater()) {\n                throw new IllegalStateException(\"Type is not a MaxUpdater: \" + type.name());\n            }\n            return updaterForCounterType[type.ordinal()];\n        }\n\n    }\n\n    /**\n     * Cumulative counters (from start of JVM) from each Type\n     */\n    /* package */static class CumulativeSum {\n        final LongAdder[] adderForCounterType;\n        final LongMaxUpdater[] updaterForCounterType;\n\n        CumulativeSum() {\n\n            /*\n             * We support both LongAdder and LongMaxUpdater in a bucket but don't want the memory allocation\n             * of all types for each so we only allocate the objects if the HystrixRollingNumberEvent matches\n             * the correct type - though we still have the allocation of empty arrays to the given length\n             * as we want to keep using the type.ordinal() value for fast random access.\n             */\n\n            // initialize the array of LongAdders\n            adderForCounterType = new LongAdder[HystrixRollingNumberEvent.values().length];\n            for (HystrixRollingNumberEvent type : HystrixRollingNumberEvent.values()) {\n                if (type.isCounter()) {\n                    adderForCounterType[type.ordinal()] = new LongAdder();\n                }\n            }\n\n            updaterForCounterType = new LongMaxUpdater[HystrixRollingNumberEvent.values().length];\n            for (HystrixRollingNumberEvent type : HystrixRollingNumberEvent.values()) {\n                if (type.isMaxUpdater()) {\n                    updaterForCounterType[type.ordinal()] = new LongMaxUpdater();\n                    // initialize to 0 otherwise it is Long.MIN_VALUE\n                    updaterForCounterType[type.ordinal()].update(0);\n                }\n            }\n        }\n\n        public void addBucket(Bucket lastBucket) {\n            for (HystrixRollingNumberEvent type : HystrixRollingNumberEvent.values()) {\n                if (type.isCounter()) {\n                    getAdder(type).add(lastBucket.getAdder(type).sum());\n                }\n                if (type.isMaxUpdater()) {\n                    getMaxUpdater(type).update(lastBucket.getMaxUpdater(type).max());\n                }\n            }\n        }\n\n        long get(HystrixRollingNumberEvent type) {\n            if (type.isCounter()) {\n                return adderForCounterType[type.ordinal()].sum();\n            }\n            if (type.isMaxUpdater()) {\n                return updaterForCounterType[type.ordinal()].max();\n            }\n            throw new IllegalStateException(\"Unknown type of event: \" + type.name());\n        }\n\n        LongAdder getAdder(HystrixRollingNumberEvent type) {\n            if (!type.isCounter()) {\n                throw new IllegalStateException(\"Type is not a Counter: \" + type.name());\n            }\n            return adderForCounterType[type.ordinal()];\n        }\n\n        LongMaxUpdater getMaxUpdater(HystrixRollingNumberEvent type) {\n            if (!type.isMaxUpdater()) {\n                throw new IllegalStateException(\"Type is not a MaxUpdater: \" + type.name());\n            }\n            return updaterForCounterType[type.ordinal()];\n        }\n\n    }\n\n    /**\n     * This is a circular array acting as a FIFO queue.\n     * <p>\n     * It purposefully does NOT implement Deque or some other Collection interface as it only implements functionality necessary for this RollingNumber use case.\n     * <p>\n     * Important Thread-Safety Note: This is ONLY thread-safe within the context of RollingNumber and the protection it gives in the <code>getCurrentBucket</code> method. It uses AtomicReference\n     * objects to ensure anything done outside of <code>getCurrentBucket</code> is thread-safe, and to ensure visibility of changes across threads (ie. volatility) but the addLast and removeFirst\n     * methods are NOT thread-safe for external access they depend upon the lock.tryLock() protection in <code>getCurrentBucket</code> which ensures only a single thread will access them at at time.\n     * <p>\n     * benjchristensen => This implementation was chosen based on performance testing I did and documented at: http://benjchristensen.com/2011/10/08/atomiccirculararray/\n     */\n    /* package */static class BucketCircularArray implements Iterable<Bucket> {\n        private final AtomicReference<ListState> state;\n        private final int dataLength; // we don't resize, we always stay the same, so remember this\n        private final int numBuckets;\n\n        /**\n         * Immutable object that is atomically set every time the state of the BucketCircularArray changes\n         * <p>\n         * This handles the compound operations\n         */\n        private class ListState {\n            /*\n             * this is an AtomicReferenceArray and not a normal Array because we're copying the reference\n             * between ListState objects and multiple threads could maintain references across these\n             * compound operations so I want the visibility/concurrency guarantees\n             */\n            private final AtomicReferenceArray<Bucket> data;\n            private final int size;\n            private final int tail;\n            private final int head;\n\n            private ListState(AtomicReferenceArray<Bucket> data, int head, int tail) {\n                this.head = head;\n                this.tail = tail;\n                if (head == 0 && tail == 0) {\n                    size = 0;\n                } else {\n                    this.size = (tail + dataLength - head) % dataLength;\n                }\n                this.data = data;\n            }\n\n            public Bucket tail() {\n                if (size == 0) {\n                    return null;\n                } else {\n                    // we want to get the last item, so size()-1\n                    return data.get(convert(size - 1));\n                }\n            }\n\n            private Bucket[] getArray() {\n                /*\n                 * this isn't technically thread-safe since it requires multiple reads on something that can change\n                 * but since we never clear the data directly, only increment/decrement head/tail we would never get a NULL\n                 * just potentially return stale data which we are okay with doing\n                 */\n                ArrayList<Bucket> array = new ArrayList<Bucket>();\n                for (int i = 0; i < size; i++) {\n                    array.add(data.get(convert(i)));\n                }\n                return array.toArray(new Bucket[array.size()]);\n            }\n\n            private ListState incrementTail() {\n                /* if incrementing results in growing larger than 'length' which is the max we should be at, then also increment head (equivalent of removeFirst but done atomically) */\n                if (size == numBuckets) {\n                    // increment tail and head\n                    return new ListState(data, (head + 1) % dataLength, (tail + 1) % dataLength);\n                } else {\n                    // increment only tail\n                    return new ListState(data, head, (tail + 1) % dataLength);\n                }\n            }\n\n            public ListState clear() {\n                return new ListState(new AtomicReferenceArray<Bucket>(dataLength), 0, 0);\n            }\n\n            public ListState addBucket(Bucket b) {\n                /*\n                 * We could in theory have 2 threads addBucket concurrently and this compound operation would interleave.\n                 * <p>\n                 * This should NOT happen since getCurrentBucket is supposed to be executed by a single thread.\n                 * <p>\n                 * If it does happen, it's not a huge deal as incrementTail() will be protected by compareAndSet and one of the two addBucket calls will succeed with one of the Buckets.\n                 * <p>\n                 * In either case, a single Bucket will be returned as \"last\" and data loss should not occur and everything keeps in sync for head/tail.\n                 * <p>\n                 * Also, it's fine to set it before incrementTail because nothing else should be referencing that index position until incrementTail occurs.\n                 */\n                data.set(tail, b);\n                return incrementTail();\n            }\n\n            // The convert() method takes a logical index (as if head was\n            // always 0) and calculates the index within elementData\n            private int convert(int index) {\n                return (index + head) % dataLength;\n            }\n        }\n\n        BucketCircularArray(int size) {\n            AtomicReferenceArray<Bucket> _buckets = new AtomicReferenceArray<Bucket>(size + 1); // + 1 as extra room for the add/remove;\n            state = new AtomicReference<ListState>(new ListState(_buckets, 0, 0));\n            dataLength = _buckets.length();\n            numBuckets = size;\n        }\n\n        public void clear() {\n            while (true) {\n                /*\n                 * it should be very hard to not succeed the first pass thru since this is typically is only called from\n                 * a single thread protected by a tryLock, but there is at least 1 other place (at time of writing this comment)\n                 * where reset can be called from (CircuitBreaker.markSuccess after circuit was tripped) so it can\n                 * in an edge-case conflict.\n                 * \n                 * Instead of trying to determine if someone already successfully called clear() and we should skip\n                 * we will have both calls reset the circuit, even if that means losing data added in between the two\n                 * depending on thread scheduling.\n                 * \n                 * The rare scenario in which that would occur, we'll accept the possible data loss while clearing it\n                 * since the code has stated its desire to clear() anyways.\n                 */\n                ListState current = state.get();\n                ListState newState = current.clear();\n                if (state.compareAndSet(current, newState)) {\n                    return;\n                }\n            }\n        }\n\n        /**\n         * Returns an iterator on a copy of the internal array so that the iterator won't fail by buckets being added/removed concurrently.\n         */\n        public Iterator<Bucket> iterator() {\n            return Collections.unmodifiableList(Arrays.asList(getArray())).iterator();\n        }\n\n        public void addLast(Bucket o) {\n            ListState currentState = state.get();\n            // create new version of state (what we want it to become)\n            ListState newState = currentState.addBucket(o);\n\n            /*\n             * use compareAndSet to set in case multiple threads are attempting (which shouldn't be the case because since addLast will ONLY be called by a single thread at a time due to protection\n             * provided in <code>getCurrentBucket</code>)\n             */\n            if (state.compareAndSet(currentState, newState)) {\n                // we succeeded\n                return;\n            } else {\n                // we failed, someone else was adding or removing\n                // instead of trying again and risking multiple addLast concurrently (which shouldn't be the case)\n                // we'll just return and let the other thread 'win' and if the timing is off the next call to getCurrentBucket will fix things\n                return;\n            }\n        }\n\n        public Bucket getLast() {\n            return peekLast();\n        }\n\n        public int size() {\n            // the size can also be worked out each time as:\n            // return (tail + data.length() - head) % data.length();\n            return state.get().size;\n        }\n\n        public Bucket peekLast() {\n            return state.get().tail();\n        }\n\n        private Bucket[] getArray() {\n            return state.get().getArray();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixRollingNumberEvent.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport com.netflix.hystrix.HystrixEventType;\n\n/**\n * Various states/events that can be captured in the {@link HystrixRollingNumber}.\n * <p>\n * Note that events are defined as different types:\n * <ul>\n * <li>Counter: <code>isCounter() == true</code></li>\n * <li>MaxUpdater: <code>isMaxUpdater() == true</code></li>\n * </ul>\n * <p>\n * The Counter type events can be used with {@link HystrixRollingNumber#increment}, {@link HystrixRollingNumber#add}, {@link HystrixRollingNumber#getRollingSum} and others.\n * <p>\n * The MaxUpdater type events can be used with {@link HystrixRollingNumber#updateRollingMax} and {@link HystrixRollingNumber#getRollingMaxValue}.\n */\npublic enum HystrixRollingNumberEvent {\n    SUCCESS(1), FAILURE(1), TIMEOUT(1), SHORT_CIRCUITED(1), THREAD_POOL_REJECTED(1), SEMAPHORE_REJECTED(1), BAD_REQUEST(1),\n    FALLBACK_SUCCESS(1), FALLBACK_FAILURE(1), FALLBACK_REJECTION(1), FALLBACK_DISABLED(1), FALLBACK_MISSING(1), EXCEPTION_THROWN(1), COMMAND_MAX_ACTIVE(2), EMIT(1), FALLBACK_EMIT(1),\n    THREAD_EXECUTION(1), THREAD_MAX_ACTIVE(2), COLLAPSED(1), RESPONSE_FROM_CACHE(1),\n    COLLAPSER_REQUEST_BATCHED(1), COLLAPSER_BATCH(1);\n\n    private final int type;\n\n    private HystrixRollingNumberEvent(int type) {\n        this.type = type;\n    }\n\n    public boolean isCounter() {\n        return type == 1;\n    }\n\n    public boolean isMaxUpdater() {\n        return type == 2;\n    }\n\n    public static HystrixRollingNumberEvent from(HystrixEventType eventType) {\n        switch (eventType) {\n            case BAD_REQUEST: return HystrixRollingNumberEvent.BAD_REQUEST;\n            case COLLAPSED: return HystrixRollingNumberEvent.COLLAPSED;\n            case EMIT: return HystrixRollingNumberEvent.EMIT;\n            case EXCEPTION_THROWN: return HystrixRollingNumberEvent.EXCEPTION_THROWN;\n            case FAILURE: return HystrixRollingNumberEvent.FAILURE;\n            case FALLBACK_EMIT: return HystrixRollingNumberEvent.FALLBACK_EMIT;\n            case FALLBACK_FAILURE: return HystrixRollingNumberEvent.FALLBACK_FAILURE;\n            case FALLBACK_DISABLED: return HystrixRollingNumberEvent.FALLBACK_DISABLED;\n            case FALLBACK_MISSING: return HystrixRollingNumberEvent.FALLBACK_MISSING;\n            case FALLBACK_REJECTION: return HystrixRollingNumberEvent.FALLBACK_REJECTION;\n            case FALLBACK_SUCCESS: return HystrixRollingNumberEvent.FALLBACK_SUCCESS;\n            case RESPONSE_FROM_CACHE: return HystrixRollingNumberEvent.RESPONSE_FROM_CACHE;\n            case SEMAPHORE_REJECTED: return HystrixRollingNumberEvent.SEMAPHORE_REJECTED;\n            case SHORT_CIRCUITED: return HystrixRollingNumberEvent.SHORT_CIRCUITED;\n            case SUCCESS: return HystrixRollingNumberEvent.SUCCESS;\n            case THREAD_POOL_REJECTED: return HystrixRollingNumberEvent.THREAD_POOL_REJECTED;\n            case TIMEOUT: return HystrixRollingNumberEvent.TIMEOUT;\n            default: throw new RuntimeException(\"Unknown HystrixEventType : \" + eventType);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixRollingPercentile.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicIntegerArray;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.atomic.AtomicReferenceArray;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\n\n/**\n * Add values to a rolling window and retrieve percentile calculations such as median, 90th, 99th, etc.\n * <p>\n * The underlying data structure contains a circular array of buckets that \"roll\" over time.\n * <p>\n * For example, if the time window is configured to 60 seconds with 12 buckets of 5 seconds each, values will be captured in each 5 second bucket and rotate each 5 seconds.\n * <p>\n * This means that percentile calculations are for the \"rolling window\" of 55-60 seconds up to 5 seconds ago.\n * <p>\n * Each bucket will contain a circular array of long values and if more than the configured amount (1000 values for example) it will wrap around and overwrite values until time passes and a new bucket\n * is allocated. This sampling approach for high volume metrics is done to conserve memory and reduce sorting time when calculating percentiles.\n */\npublic class HystrixRollingPercentile {\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixRollingPercentile.class);\n\n    private static final Time ACTUAL_TIME = new ActualTime();\n    private final Time time;\n    /* package for testing */ final BucketCircularArray buckets;\n    private final int timeInMilliseconds;\n    private final int numberOfBuckets;\n    private final int bucketDataLength;\n    private final int bucketSizeInMilliseconds;\n    private final HystrixProperty<Boolean> enabled;\n\n    /*\n     * This will get flipped each time a new bucket is created.\n     */\n    /* package for testing */ volatile PercentileSnapshot currentPercentileSnapshot = new PercentileSnapshot(0);\n\n    /**\n     * \n     * @param timeInMilliseconds\n     *            {@code HystrixProperty<Integer>} for number of milliseconds of data that should be tracked\n     *            Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified\n     *            at runtime, to avoid data loss\n     *            <p>\n     *            Example: 60000 for 1 minute\n     * @param numberOfBuckets\n     *            {@code HystrixProperty<Integer>} for number of buckets that the time window should be divided into\n     *            Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified\n     *            at runtime, to avoid data loss\n     *            <p>\n     *            Example: 12 for 5 second buckets in a 1 minute window\n     * @param bucketDataLength\n     *            {@code HystrixProperty<Integer>} for number of values stored in each bucket\n     *            Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified\n     *            at runtime, to avoid data loss\n     *            <p>\n     *            Example: 1000 to store a max of 1000 values in each 5 second bucket\n     * @param enabled\n     *            {@code HystrixProperty<Boolean>} whether data should be tracked and percentiles calculated.\n     *            <p>\n     *            If 'false' methods will do nothing.\n     * @deprecated Please use the constructor with non-configurable properties {@link HystrixRollingPercentile(Time, int, int, int, HystrixProperty<Boolean>}\n     */\n    @Deprecated\n    public HystrixRollingPercentile(HystrixProperty<Integer> timeInMilliseconds, HystrixProperty<Integer> numberOfBuckets, HystrixProperty<Integer> bucketDataLength, HystrixProperty<Boolean> enabled) {\n        this(timeInMilliseconds.get(), numberOfBuckets.get(), bucketDataLength.get(), enabled);\n    }\n\n    /**\n     *\n     * @param timeInMilliseconds\n     *            number of milliseconds of data that should be tracked\n     *            <p>\n     *            Example: 60000 for 1 minute\n     * @param numberOfBuckets\n     *            number of buckets that the time window should be divided into\n     *            <p>\n     *            Example: 12 for 5 second buckets in a 1 minute window\n     * @param bucketDataLength\n     *            number of values stored in each bucket\n     *            <p>\n     *            Example: 1000 to store a max of 1000 values in each 5 second bucket\n     * @param enabled\n     *            {@code HystrixProperty<Boolean>} whether data should be tracked and percentiles calculated.\n     *            <p>\n     *            If 'false' methods will do nothing.\n     */\n    public HystrixRollingPercentile(int timeInMilliseconds, int numberOfBuckets, int bucketDataLength, HystrixProperty<Boolean> enabled) {\n        this(ACTUAL_TIME, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);\n\n    }\n\n    /* package for testing */ HystrixRollingPercentile(Time time, int timeInMilliseconds, int numberOfBuckets, int bucketDataLength, HystrixProperty<Boolean> enabled) {\n        this.time = time;\n        this.timeInMilliseconds = timeInMilliseconds;\n        this.numberOfBuckets = numberOfBuckets;\n        this.bucketDataLength = bucketDataLength;\n        this.enabled = enabled;\n\n        if (this.timeInMilliseconds % this.numberOfBuckets != 0) {\n            throw new IllegalArgumentException(\"The timeInMilliseconds must divide equally into numberOfBuckets. For example 1000/10 is ok, 1000/11 is not.\");\n        }\n        this.bucketSizeInMilliseconds = this.timeInMilliseconds / this.numberOfBuckets;\n\n        buckets = new BucketCircularArray(this.numberOfBuckets);\n    }\n\n    /**\n     * Add value (or values) to current bucket.\n     * \n     * @param value\n     *            Value to be stored in current bucket such as execution latency in milliseconds\n     */\n    public void addValue(int... value) {\n        /* no-op if disabled */\n        if (!enabled.get())\n            return;\n\n        for (int v : value) {\n            try {\n                getCurrentBucket().data.addValue(v);\n            } catch (Exception e) {\n                logger.error(\"Failed to add value: \" + v, e);\n            }\n        }\n    }\n\n    /**\n     * Compute a percentile from the underlying rolling buckets of values.\n     * <p>\n     * For performance reasons it maintains a single snapshot of the sorted values from all buckets that is re-generated each time the bucket rotates.\n     * <p>\n     * This means that if a bucket is 5000ms, then this method will re-compute a percentile at most once every 5000ms.\n     * \n     * @param percentile\n     *            value such as 99 (99th percentile), 99.5 (99.5th percentile), 50 (median, 50th percentile) to compute and retrieve percentile from rolling buckets.\n     * @return int percentile value\n     */\n    public int getPercentile(double percentile) {\n        /* no-op if disabled */\n        if (!enabled.get())\n            return -1;\n\n        // force logic to move buckets forward in case other requests aren't making it happen\n        getCurrentBucket();\n        // fetch the current snapshot\n        return getCurrentPercentileSnapshot().getPercentile(percentile);\n    }\n\n    /**\n     * This returns the mean (average) of all values in the current snapshot. This is not a percentile but often desired so captured and exposed here.\n     * \n     * @return mean of all values\n     */\n    public int getMean() {\n        /* no-op if disabled */\n        if (!enabled.get())\n            return -1;\n\n        // force logic to move buckets forward in case other requests aren't making it happen\n        getCurrentBucket();\n        // fetch the current snapshot\n        return getCurrentPercentileSnapshot().getMean();\n    }\n\n    /**\n     * This will retrieve the current snapshot or create a new one if one does not exist.\n     * <p>\n     * It will NOT include data from the current bucket, but all previous buckets.\n     * <p>\n     * It remains cached until the next bucket rotates at which point a new one will be created.\n     */\n    private PercentileSnapshot getCurrentPercentileSnapshot() {\n        return currentPercentileSnapshot;\n    }\n\n    private ReentrantLock newBucketLock = new ReentrantLock();\n\n    private Bucket getCurrentBucket() {\n        long currentTime = time.getCurrentTimeInMillis();\n\n        /* a shortcut to try and get the most common result of immediately finding the current bucket */\n\n        /**\n         * Retrieve the latest bucket if the given time is BEFORE the end of the bucket window, otherwise it returns NULL.\n         * \n         * NOTE: This is thread-safe because it's accessing 'buckets' which is a LinkedBlockingDeque\n         */\n        Bucket currentBucket = buckets.peekLast();\n        if (currentBucket != null && currentTime < currentBucket.windowStart + this.bucketSizeInMilliseconds) {\n            // if we're within the bucket 'window of time' return the current one\n            // NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,\n            // we'll just use the latest as long as we're not AFTER the window\n            return currentBucket;\n        }\n\n        /* if we didn't find the current bucket above, then we have to create one */\n\n        /**\n         * The following needs to be synchronized/locked even with a synchronized/thread-safe data structure such as LinkedBlockingDeque because\n         * the logic involves multiple steps to check existence, create an object then insert the object. The 'check' or 'insertion' themselves\n         * are thread-safe by themselves but not the aggregate algorithm, thus we put this entire block of logic inside synchronized.\n         * \n         * I am using a tryLock if/then (http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/Lock.html#tryLock())\n         * so that a single thread will get the lock and as soon as one thread gets the lock all others will go the 'else' block\n         * and just return the currentBucket until the newBucket is created. This should allow the throughput to be far higher\n         * and only slow down 1 thread instead of blocking all of them in each cycle of creating a new bucket based on some testing\n         * (and it makes sense that it should as well).\n         * \n         * This means the timing won't be exact to the millisecond as to what data ends up in a bucket, but that's acceptable.\n         * It's not critical to have exact precision to the millisecond, as long as it's rolling, if we can instead reduce the impact synchronization.\n         * \n         * More importantly though it means that the 'if' block within the lock needs to be careful about what it changes that can still\n         * be accessed concurrently in the 'else' block since we're not completely synchronizing access.\n         * \n         * For example, we can't have a multi-step process to add a bucket, remove a bucket, then update the sum since the 'else' block of code\n         * can retrieve the sum while this is all happening. The trade-off is that we don't maintain the rolling sum and let readers just iterate\n         * bucket to calculate the sum themselves. This is an example of favoring write-performance instead of read-performance and how the tryLock\n         * versus a synchronized block needs to be accommodated.\n         */\n        if (newBucketLock.tryLock()) {\n            try {\n                if (buckets.peekLast() == null) {\n                    // the list is empty so create the first bucket\n                    Bucket newBucket = new Bucket(currentTime, bucketDataLength);\n                    buckets.addLast(newBucket);\n                    return newBucket;\n                } else {\n                    // We go into a loop so that it will create as many buckets as needed to catch up to the current time\n                    // as we want the buckets complete even if we don't have transactions during a period of time.\n                    for (int i = 0; i < numberOfBuckets; i++) {\n                        // we have at least 1 bucket so retrieve it\n                        Bucket lastBucket = buckets.peekLast();\n                        if (currentTime < lastBucket.windowStart + this.bucketSizeInMilliseconds) {\n                            // if we're within the bucket 'window of time' return the current one\n                            // NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,\n                            // we'll just use the latest as long as we're not AFTER the window\n                            return lastBucket;\n                        } else if (currentTime - (lastBucket.windowStart + this.bucketSizeInMilliseconds) > timeInMilliseconds) {\n                            // the time passed is greater than the entire rolling counter so we want to clear it all and start from scratch\n                            reset();\n                            // recursively call getCurrentBucket which will create a new bucket and return it\n                            return getCurrentBucket();\n                        } else { // we're past the window so we need to create a new bucket\n                            Bucket[] allBuckets = buckets.getArray();\n                            // create a new bucket and add it as the new 'last' (once this is done other threads will start using it on subsequent retrievals)\n                            buckets.addLast(new Bucket(lastBucket.windowStart + this.bucketSizeInMilliseconds, bucketDataLength));\n                            // we created a new bucket so let's re-generate the PercentileSnapshot (not including the new bucket)\n                            currentPercentileSnapshot = new PercentileSnapshot(allBuckets);\n                        }\n                    }\n                    // we have finished the for-loop and created all of the buckets, so return the lastBucket now\n                    return buckets.peekLast();\n                }\n            } finally {\n                newBucketLock.unlock();\n            }\n        } else {\n            currentBucket = buckets.peekLast();\n            if (currentBucket != null) {\n                // we didn't get the lock so just return the latest bucket while another thread creates the next one\n                return currentBucket;\n            } else {\n                // the rare scenario where multiple threads raced to create the very first bucket\n                // wait slightly and then use recursion while the other thread finishes creating a bucket\n                try {\n                    Thread.sleep(5);\n                } catch (Exception e) {\n                    // ignore\n                }\n                return getCurrentBucket();\n            }\n        }\n    }\n\n    /**\n     * Force a reset so that percentiles start being gathered from scratch.\n     */\n    public void reset() {\n        /* no-op if disabled */\n        if (!enabled.get())\n            return;\n\n        // clear buckets so we start over again\n        buckets.clear();\n\n        // and also make sure the percentile snapshot gets reset\n        currentPercentileSnapshot = new PercentileSnapshot(buckets.getArray());\n    }\n\n    /* package-private for testing */ static class PercentileBucketData {\n        private final int length;\n        private final AtomicIntegerArray list;\n        private final AtomicInteger index = new AtomicInteger();\n\n        public PercentileBucketData(int dataLength) {\n            this.length = dataLength;\n            this.list = new AtomicIntegerArray(dataLength);\n        }\n\n        public void addValue(int... latency) {\n            for (int l : latency) {\n                /* We just wrap around the beginning and over-write if we go past 'dataLength' as that will effectively cause us to \"sample\" the most recent data */\n                list.set(index.getAndIncrement() % length, l);\n                // TODO Alternative to AtomicInteger? The getAndIncrement may be a source of contention on high throughput circuits on large multi-core systems.\n                // LongAdder isn't suited to this as it is not consistent. Perhaps a different data structure that doesn't need indexed adds?\n                // A threadlocal data storage that only aggregates when fetched would be ideal. Similar to LongAdder except for accumulating lists of data.\n            }\n        }\n\n        public int length() {\n            if (index.get() > list.length()) {\n                return list.length();\n            } else {\n                return index.get();\n            }\n        }\n\n    }\n\n    /**\n     * @NotThreadSafe\n     */\n    /* package for testing */ static class PercentileSnapshot {\n        private final int[] data;\n        private final int length;\n        private int mean;\n\n        /* package for testing */ PercentileSnapshot(Bucket[] buckets) {\n            int lengthFromBuckets = 0;\n            // we need to calculate it dynamically as it could have been changed by properties (rare, but possible)\n            // also this way we capture the actual index size rather than the max so size the int[] to only what we need\n            for (Bucket bd : buckets) {\n                lengthFromBuckets += bd.data.length;\n            }\n            data = new int[lengthFromBuckets];\n            int index = 0;\n            int sum = 0;\n            for (Bucket bd : buckets) {\n                PercentileBucketData pbd = bd.data;\n                int length = pbd.length();\n                for (int i = 0; i < length; i++) {\n                    int v = pbd.list.get(i);\n                    this.data[index++] = v;\n                    sum += v;\n                }\n            }\n            this.length = index;\n            if (this.length == 0) {\n                this.mean = 0;\n            } else {\n                this.mean = sum / this.length;\n            }\n\n            Arrays.sort(this.data, 0, length);\n        }\n\n        /* package for testing */ PercentileSnapshot(int... data) {\n            this.data = data;\n            this.length = data.length;\n\n            int sum = 0;\n            for (int v : data) {\n                sum += v;\n            }\n            this.mean = sum / this.length;\n\n            Arrays.sort(this.data, 0, length);\n        }\n\n        /* package for testing */ int getMean() {\n            return mean;\n        }\n\n        /**\n         * Provides percentile computation.\n         */\n        public int getPercentile(double percentile) {\n            if (length == 0) {\n                return 0;\n            }\n            return computePercentile(percentile);\n        }\n\n        /**\n         * @see <a href=\"http://en.wikipedia.org/wiki/Percentile\">Percentile (Wikipedia)</a>\n         * @see <a href=\"http://cnx.org/content/m10805/latest/\">Percentile</a>\n         * \n         * @param percent percentile of data desired\n         * @return data at the asked-for percentile.  Interpolation is used if exactness is not possible\n         */\n        private int computePercentile(double percent) {\n            // Some just-in-case edge cases\n            if (length <= 0) {\n                return 0;\n            } else if (percent <= 0.0) {\n                return data[0];\n            } else if (percent >= 100.0) {\n                return data[length - 1];\n            }\n\n            // ranking (http://en.wikipedia.org/wiki/Percentile#Alternative_methods)\n            double rank = (percent / 100.0) * length;\n\n            // linear interpolation between closest ranks\n            int iLow = (int) Math.floor(rank);\n            int iHigh = (int) Math.ceil(rank);\n            assert 0 <= iLow && iLow <= rank && rank <= iHigh && iHigh <= length;\n            assert (iHigh - iLow) <= 1;\n            if (iHigh >= length) {\n                // Another edge case\n                return data[length - 1];\n            } else if (iLow == iHigh) {\n                return data[iLow];\n            } else {\n                // Interpolate between the two bounding values\n                return (int) (data[iLow] + (rank - iLow) * (data[iHigh] - data[iLow]));\n            }\n        }\n\n    }\n\n    /**\n     * This is a circular array acting as a FIFO queue.\n     * <p>\n     * It purposefully does NOT implement Deque or some other Collection interface as it only implements functionality necessary for this RollingNumber use case.\n     * <p>\n     * Important Thread-Safety Note: This is ONLY thread-safe within the context of RollingNumber and the protection it gives in the <code>getCurrentBucket</code> method. It uses AtomicReference\n     * objects to ensure anything done outside of <code>getCurrentBucket</code> is thread-safe, and to ensure visibility of changes across threads (ie. volatility) but the addLast and removeFirst\n     * methods are NOT thread-safe for external access they depend upon the lock.tryLock() protection in <code>getCurrentBucket</code> which ensures only a single thread will access them at at time.\n     * <p>\n     * benjchristensen => This implementation was chosen based on performance testing I did and documented at: http://benjchristensen.com/2011/10/08/atomiccirculararray/\n     */\n    /* package for testing */ static class BucketCircularArray implements Iterable<Bucket> {\n        private final AtomicReference<ListState> state;\n        private final int dataLength; // we don't resize, we always stay the same, so remember this\n        private final int numBuckets;\n\n        /**\n         * Immutable object that is atomically set every time the state of the BucketCircularArray changes\n         * <p>\n         * This handles the compound operations\n         */\n        private class ListState {\n            /*\n             * this is an AtomicReferenceArray and not a normal Array because we're copying the reference\n             * between ListState objects and multiple threads could maintain references across these\n             * compound operations so I want the visibility/concurrency guarantees\n             */\n            private final AtomicReferenceArray<Bucket> data;\n            private final int size;\n            private final int tail;\n            private final int head;\n\n            private ListState(AtomicReferenceArray<Bucket> data, int head, int tail) {\n                this.head = head;\n                this.tail = tail;\n                if (head == 0 && tail == 0) {\n                    size = 0;\n                } else {\n                    this.size = (tail + dataLength - head) % dataLength;\n                }\n                this.data = data;\n            }\n\n            public Bucket tail() {\n                if (size == 0) {\n                    return null;\n                } else {\n                    // we want to get the last item, so size()-1\n                    return data.get(convert(size - 1));\n                }\n            }\n\n            private Bucket[] getArray() {\n                /*\n                 * this isn't technically thread-safe since it requires multiple reads on something that can change\n                 * but since we never clear the data directly, only increment/decrement head/tail we would never get a NULL\n                 * just potentially return stale data which we are okay with doing\n                 */\n                ArrayList<Bucket> array = new ArrayList<Bucket>();\n                for (int i = 0; i < size; i++) {\n                    array.add(data.get(convert(i)));\n                }\n                return array.toArray(new Bucket[array.size()]);\n            }\n\n            private ListState incrementTail() {\n                /* if incrementing results in growing larger than 'length' which is the max we should be at, then also increment head (equivalent of removeFirst but done atomically) */\n                if (size == numBuckets) {\n                    // increment tail and head\n                    return new ListState(data, (head + 1) % dataLength, (tail + 1) % dataLength);\n                } else {\n                    // increment only tail\n                    return new ListState(data, head, (tail + 1) % dataLength);\n                }\n            }\n\n            public ListState clear() {\n                return new ListState(new AtomicReferenceArray<Bucket>(dataLength), 0, 0);\n            }\n\n            public ListState addBucket(Bucket b) {\n                /*\n                 * We could in theory have 2 threads addBucket concurrently and this compound operation would interleave.\n                 * <p>\n                 * This should NOT happen since getCurrentBucket is supposed to be executed by a single thread.\n                 * <p>\n                 * If it does happen, it's not a huge deal as incrementTail() will be protected by compareAndSet and one of the two addBucket calls will succeed with one of the Buckets.\n                 * <p>\n                 * In either case, a single Bucket will be returned as \"last\" and data loss should not occur and everything keeps in sync for head/tail.\n                 * <p>\n                 * Also, it's fine to set it before incrementTail because nothing else should be referencing that index position until incrementTail occurs.\n                 */\n                data.set(tail, b);\n                return incrementTail();\n            }\n\n            // The convert() method takes a logical index (as if head was\n            // always 0) and calculates the index within elementData\n            private int convert(int index) {\n                return (index + head) % dataLength;\n            }\n        }\n\n        BucketCircularArray(int size) {\n            AtomicReferenceArray<Bucket> _buckets = new AtomicReferenceArray<Bucket>(size + 1); // + 1 as extra room for the add/remove;\n            state = new AtomicReference<ListState>(new ListState(_buckets, 0, 0));\n            dataLength = _buckets.length();\n            numBuckets = size;\n        }\n\n        public void clear() {\n            while (true) {\n                /*\n                 * it should be very hard to not succeed the first pass thru since this is typically is only called from\n                 * a single thread protected by a tryLock, but there is at least 1 other place (at time of writing this comment)\n                 * where reset can be called from (CircuitBreaker.markSuccess after circuit was tripped) so it can\n                 * in an edge-case conflict.\n                 * \n                 * Instead of trying to determine if someone already successfully called clear() and we should skip\n                 * we will have both calls reset the circuit, even if that means losing data added in between the two\n                 * depending on thread scheduling.\n                 * \n                 * The rare scenario in which that would occur, we'll accept the possible data loss while clearing it\n                 * since the code has stated its desire to clear() anyways.\n                 */\n                ListState current = state.get();\n                ListState newState = current.clear();\n                if (state.compareAndSet(current, newState)) {\n                    return;\n                }\n            }\n        }\n\n        /**\n         * Returns an iterator on a copy of the internal array so that the iterator won't fail by buckets being added/removed concurrently.\n         */\n        public Iterator<Bucket> iterator() {\n            return Collections.unmodifiableList(Arrays.asList(getArray())).iterator();\n        }\n\n        public void addLast(Bucket o) {\n            ListState currentState = state.get();\n            // create new version of state (what we want it to become)\n            ListState newState = currentState.addBucket(o);\n\n            /*\n             * use compareAndSet to set in case multiple threads are attempting (which shouldn't be the case because since addLast will ONLY be called by a single thread at a time due to protection\n             * provided in <code>getCurrentBucket</code>)\n             */\n            if (state.compareAndSet(currentState, newState)) {\n                // we succeeded\n                return;\n            } else {\n                // we failed, someone else was adding or removing\n                // instead of trying again and risking multiple addLast concurrently (which shouldn't be the case)\n                // we'll just return and let the other thread 'win' and if the timing is off the next call to getCurrentBucket will fix things\n                return;\n            }\n        }\n\n        public int size() {\n            // the size can also be worked out each time as:\n            // return (tail + data.length() - head) % data.length();\n            return state.get().size;\n        }\n\n        public Bucket peekLast() {\n            return state.get().tail();\n        }\n\n        private Bucket[] getArray() {\n            return state.get().getArray();\n        }\n\n    }\n\n    /**\n     * Counters for a given 'bucket' of time.\n     */\n    /* package for testing */ static class Bucket {\n        final long windowStart;\n        final PercentileBucketData data;\n\n        Bucket(long startTime, int bucketDataLength) {\n            this.windowStart = startTime;\n            this.data = new PercentileBucketData(bucketDataLength);\n        }\n\n    }\n\n    /* package for testing */ static interface Time {\n        public long getCurrentTimeInMillis();\n    }\n\n    private static class ActualTime implements Time {\n\n        @Override\n        public long getCurrentTimeInMillis() {\n            return System.currentTimeMillis();\n        }\n\n    }\n\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixTimer.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.ref.Reference;\nimport java.lang.ref.SoftReference;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Timer used by {@link HystrixCommand} to timeout async executions and {@link HystrixCollapser} to trigger batch executions.\n */\npublic class HystrixTimer {\n\n    private static final Logger logger = LoggerFactory.getLogger(HystrixTimer.class);\n\n    private static HystrixTimer INSTANCE = new HystrixTimer();\n\n    private HystrixTimer() {\n        // private to prevent public instantiation\n    }\n\n    /**\n     * Retrieve the global instance.\n     */\n    public static HystrixTimer getInstance() {\n        return INSTANCE;\n    }\n\n    /**\n     * Clears all listeners.\n     * <p>\n     * NOTE: This will result in race conditions if {@link #addTimerListener(com.netflix.hystrix.util.HystrixTimer.TimerListener)} is being concurrently called.\n     * </p>\n     */\n    public static void reset() {\n        ScheduledExecutor ex = INSTANCE.executor.getAndSet(null);\n        if (ex != null && ex.getThreadPool() != null) {\n            ex.getThreadPool().shutdownNow();\n        }\n    }\n\n    /* package */ AtomicReference<ScheduledExecutor> executor = new AtomicReference<ScheduledExecutor>();\n\n    /**\n     * Add a {@link TimerListener} that will be executed until it is garbage collected or removed by clearing the returned {@link Reference}.\n     * <p>\n     * NOTE: It is the responsibility of code that adds a listener via this method to clear this listener when completed.\n     * <p>\n     * <blockquote>\n     * \n     * <pre> {@code\n     * // add a TimerListener \n     * Reference<TimerListener> listener = HystrixTimer.getInstance().addTimerListener(listenerImpl);\n     * \n     * // sometime later, often in a thread shutdown, request cleanup, servlet filter or something similar the listener must be shutdown via the clear() method\n     * listener.clear();\n     * }</pre>\n     * </blockquote>\n     * \n     * \n     * @param listener\n     *            TimerListener implementation that will be triggered according to its <code>getIntervalTimeInMilliseconds()</code> method implementation.\n     * @return reference to the TimerListener that allows cleanup via the <code>clear()</code> method\n     */\n    public Reference<TimerListener> addTimerListener(final TimerListener listener) {\n        startThreadIfNeeded();\n        // add the listener\n\n        Runnable r = new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    listener.tick();\n                } catch (Exception e) {\n                    logger.error(\"Failed while ticking TimerListener\", e);\n                }\n            }\n        };\n\n        ScheduledFuture<?> f = executor.get().getThreadPool().scheduleAtFixedRate(r, listener.getIntervalTimeInMilliseconds(), listener.getIntervalTimeInMilliseconds(), TimeUnit.MILLISECONDS);\n        return new TimerReference(listener, f);\n    }\n\n    private static class TimerReference extends SoftReference<TimerListener> {\n\n        private final ScheduledFuture<?> f;\n\n        TimerReference(TimerListener referent, ScheduledFuture<?> f) {\n            super(referent);\n            this.f = f;\n        }\n\n        @Override\n        public void clear() {\n            super.clear();\n            // stop this ScheduledFuture from any further executions\n            f.cancel(false);\n        }\n\n    }\n\n    /**\n     * Since we allow resetting the timer (shutting down the thread) we need to lazily re-start it if it starts being used again.\n     * <p>\n     * This does the lazy initialization and start of the thread in a thread-safe manner while having little cost the rest of the time.\n     */\n    protected void startThreadIfNeeded() {\n        // create and start thread if one doesn't exist\n        while (executor.get() == null || ! executor.get().isInitialized()) {\n            if (executor.compareAndSet(null, new ScheduledExecutor())) {\n                // initialize the executor that we 'won' setting\n                executor.get().initialize();\n            }\n        }\n    }\n\n    /* package */ static class ScheduledExecutor {\n        /* package */ volatile ScheduledThreadPoolExecutor executor;\n        private volatile boolean initialized;\n\n        /**\n         * We want this only done once when created in compareAndSet so use an initialize method\n         */\n        public void initialize() {\n\n            HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();\n            int coreSize = propertiesStrategy.getTimerThreadPoolProperties().getCorePoolSize().get();\n\n            ThreadFactory threadFactory = null;\n            if (!PlatformSpecific.isAppEngineStandardEnvironment()) {\n                threadFactory = new ThreadFactory() {\n                    final AtomicInteger counter = new AtomicInteger();\n\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        Thread thread = new Thread(r, \"HystrixTimer-\" + counter.incrementAndGet());\n                        thread.setDaemon(true);\n                        return thread;\n                    }\n\n                };\n            } else {\n                threadFactory = PlatformSpecific.getAppEngineThreadFactory();\n            }\n\n            executor = new ScheduledThreadPoolExecutor(coreSize, threadFactory);\n            initialized = true;\n        }\n\n        public ScheduledThreadPoolExecutor getThreadPool() {\n            return executor;\n        }\n\n        public boolean isInitialized() {\n            return initialized;\n        }\n    }\n\n    public static interface TimerListener {\n\n        /**\n         * The 'tick' is called each time the interval occurs.\n         * <p>\n         * This method should NOT block or do any work but instead fire its work asynchronously to perform on another thread otherwise it will prevent the Timer from functioning.\n         * <p>\n         * This contract is used to keep this implementation single-threaded and simplistic.\n         * <p>\n         * If you need a ThreadLocal set, you can store the state in the TimerListener, then when tick() is called, set the ThreadLocal to your desired value.\n         */\n        public void tick();\n\n        /**\n         * How often this TimerListener should 'tick' defined in milliseconds.\n         */\n        public int getIntervalTimeInMilliseconds();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/InternMap.java",
    "content": "package com.netflix.hystrix.util;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Utility to have 'intern' - like functionality, which holds single instance of wrapper for a given key\n */\npublic class InternMap<K, V> {\n    private final ConcurrentMap<K, V> storage = new ConcurrentHashMap<K, V>();\n    private final ValueConstructor<K, V> valueConstructor;\n\n    public interface ValueConstructor<K, V> {\n        V create(K key);\n    }\n\n    public InternMap(ValueConstructor<K, V> valueConstructor) {\n        this.valueConstructor = valueConstructor;\n    }\n\n    public V interned(K key) {\n        V existingKey = storage.get(key);\n        V newKey = null;\n        if (existingKey == null) {\n            newKey = valueConstructor.create(key);\n            existingKey = storage.putIfAbsent(key, newKey);\n        }\n        return existingKey != null ? existingKey : newKey;\n    }\n\n    public int size() {\n        return storage.size();\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/LongAdder.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\n/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/publicdomain/zero/1.0/\n * \n * From http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/\n */\n\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.Serializable;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * One or more variables that together maintain an initially zero\n * {@code long} sum.  When updates (method {@link #add}) are contended\n * across threads, the set of variables may grow dynamically to reduce\n * contention. Method {@link #sum} (or, equivalently, {@link\n * #longValue}) returns the current total combined across the\n * variables maintaining the sum.\n *\n * <p> This class is usually preferable to {@link AtomicLong} when\n * multiple threads update a common sum that is used for purposes such\n * as collecting statistics, not for fine-grained synchronization\n * control.  Under low update contention, the two classes have similar\n * characteristics. But under high contention, expected throughput of\n * this class is significantly higher, at the expense of higher space\n * consumption.\n *\n * <p>This class extends {@link Number}, but does <em>not</em> define\n * methods such as {@code hashCode} and {@code compareTo} because\n * instances are expected to be mutated, and so are not useful as\n * collection keys.\n *\n * <p><em>jsr166e note: This class is targeted to be placed in\n * java.util.concurrent.atomic<em>\n *\n * @since 1.8\n * @author Doug Lea\n */\npublic class LongAdder extends Striped64 implements Serializable {\n    private static final long serialVersionUID = 7249069246863182397L;\n\n    /**\n     * Version of plus for use in retryUpdate\n     */\n    final long fn(long v, long x) { return v + x; }\n\n    /**\n     * Creates a new adder with initial sum of zero.\n     */\n    public LongAdder() {\n    }\n\n    /**\n     * Adds the given value.\n     *\n     * @param x the value to add\n     */\n    public void add(long x) {\n        Cell[] as; long b, v; HashCode hc; Cell a; int n;\n        if ((as = cells) != null || !casBase(b = base, b + x)) {\n            boolean uncontended = true;\n            int h = (hc = threadHashCode.get()).code;\n            if (as == null || (n = as.length) < 1 ||\n                (a = as[(n - 1) & h]) == null ||\n                !(uncontended = a.cas(v = a.value, v + x)))\n                retryUpdate(x, hc, uncontended);\n        }\n    }\n\n    /**\n     * Equivalent to {@code add(1)}.\n     */\n    public void increment() {\n        add(1L);\n    }\n\n    /**\n     * Equivalent to {@code add(-1)}.\n     */\n    public void decrement() {\n        add(-1L);\n    }\n\n    /**\n     * Returns the current sum.  The returned value is <em>NOT</em> an\n     * atomic snapshot: Invocation in the absence of concurrent\n     * updates returns an accurate result, but concurrent updates that\n     * occur while the sum is being calculated might not be\n     * incorporated.\n     *\n     * @return the sum\n     */\n    public long sum() {\n        long sum = base;\n        Cell[] as = cells;\n        if (as != null) {\n            int n = as.length;\n            for (int i = 0; i < n; ++i) {\n                Cell a = as[i];\n                if (a != null)\n                    sum += a.value;\n            }\n        }\n        return sum;\n    }\n\n    /**\n     * Resets variables maintaining the sum to zero.  This method may\n     * be a useful alternative to creating a new adder, but is only\n     * effective if there are no concurrent updates.  Because this\n     * method is intrinsically racy, it should only be used when it is\n     * known that no threads are concurrently updating.\n     */\n    public void reset() {\n        internalReset(0L);\n    }\n\n    /**\n     * Equivalent in effect to {@link #sum} followed by {@link\n     * #reset}. This method may apply for example during quiescent\n     * points between multithreaded computations.  If there are\n     * updates concurrent with this method, the returned value is\n     * <em>not</em> guaranteed to be the final value occurring before\n     * the reset.\n     *\n     * @return the sum\n     */\n    public long sumThenReset() {\n        long sum = base;\n        Cell[] as = cells;\n        base = 0L;\n        if (as != null) {\n            int n = as.length;\n            for (int i = 0; i < n; ++i) {\n                Cell a = as[i];\n                if (a != null) {\n                    sum += a.value;\n                    a.value = 0L;\n                }\n            }\n        }\n        return sum;\n    }\n\n    /**\n     * Returns the String representation of the {@link #sum}.\n     * @return the String representation of the {@link #sum}\n     */\n    public String toString() {\n        return Long.toString(sum());\n    }\n\n    /**\n     * Equivalent to {@link #sum}.\n     *\n     * @return the sum\n     */\n    public long longValue() {\n        return sum();\n    }\n\n    /**\n     * Returns the {@link #sum} as an {@code int} after a narrowing\n     * primitive conversion.\n     */\n    public int intValue() {\n        return (int)sum();\n    }\n\n    /**\n     * Returns the {@link #sum} as a {@code float}\n     * after a widening primitive conversion.\n     */\n    public float floatValue() {\n        return (float)sum();\n    }\n\n    /**\n     * Returns the {@link #sum} as a {@code double} after a widening\n     * primitive conversion.\n     */\n    public double doubleValue() {\n        return (double)sum();\n    }\n\n    private void writeObject(java.io.ObjectOutputStream s)\n        throws java.io.IOException {\n        s.defaultWriteObject();\n        s.writeLong(sum());\n    }\n\n    private void readObject(ObjectInputStream s)\n        throws IOException, ClassNotFoundException {\n        s.defaultReadObject();\n        busy = 0;\n        cells = null;\n        base = s.readLong();\n    }\n\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/LongMaxUpdater.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\n/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/publicdomain/zero/1.0/\n * \n * From http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/\n */\n\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.Serializable;\n\n/**\n * One or more variables that together maintain a running {@code long}\n * maximum with initial value {@code Long.MIN_VALUE}.  When updates\n * (method {@link #update}) are contended across threads, the set of\n * variables may grow dynamically to reduce contention.  Method {@link\n * #max} (or, equivalently, {@link #longValue}) returns the current\n * maximum across the variables maintaining updates.\n *\n * <p>This class extends {@link Number}, but does <em>not</em> define\n * methods such as {@code hashCode} and {@code compareTo} because\n * instances are expected to be mutated, and so are not useful as\n * collection keys.\n *\n * <p><em>jsr166e note: This class is targeted to be placed in\n * java.util.concurrent.atomic<em>\n *\n * @since 1.8\n * @author Doug Lea\n */\npublic class LongMaxUpdater extends Striped64 implements Serializable {\n    private static final long serialVersionUID = 7249069246863182397L;\n\n    /**\n     * Version of max for use in retryUpdate\n     */\n    final long fn(long v, long x) { return v > x ? v : x; }\n\n    /**\n     * Creates a new instance with initial maximum of {@code\n     * Long.MIN_VALUE}.\n     */\n    public LongMaxUpdater() {\n        base = Long.MIN_VALUE;\n    }\n\n    /**\n     * Updates the maximum to be at least the given value.\n     *\n     * @param x the value to update\n     */\n    public void update(long x) {\n        Cell[] as; long b, v; HashCode hc; Cell a; int n;\n        if ((as = cells) != null ||\n            (b = base) < x && !casBase(b, x)) {\n            boolean uncontended = true;\n            int h = (hc = threadHashCode.get()).code;\n            if (as == null || (n = as.length) < 1 ||\n                (a = as[(n - 1) & h]) == null ||\n                ((v = a.value) < x && !(uncontended = a.cas(v, x))))\n                retryUpdate(x, hc, uncontended);\n        }\n    }\n\n    /**\n     * Returns the current maximum.  The returned value is\n     * <em>NOT</em> an atomic snapshot: Invocation in the absence of\n     * concurrent updates returns an accurate result, but concurrent\n     * updates that occur while the value is being calculated might\n     * not be incorporated.\n     *\n     * @return the maximum\n     */\n    public long max() {\n        Cell[] as = cells;\n        long max = base;\n        if (as != null) {\n            int n = as.length;\n            long v;\n            for (int i = 0; i < n; ++i) {\n                Cell a = as[i];\n                if (a != null && (v = a.value) > max)\n                    max = v;\n            }\n        }\n        return max;\n    }\n\n    /**\n     * Resets variables maintaining updates to {@code Long.MIN_VALUE}.\n     * This method may be a useful alternative to creating a new\n     * updater, but is only effective if there are no concurrent\n     * updates.  Because this method is intrinsically racy, it should\n     * only be used when it is known that no threads are concurrently\n     * updating.\n     */\n    public void reset() {\n        internalReset(Long.MIN_VALUE);\n    }\n\n    /**\n     * Equivalent in effect to {@link #max} followed by {@link\n     * #reset}. This method may apply for example during quiescent\n     * points between multithreaded computations.  If there are\n     * updates concurrent with this method, the returned value is\n     * <em>not</em> guaranteed to be the final value occurring before\n     * the reset.\n     *\n     * @return the maximum\n     */\n    public long maxThenReset() {\n        Cell[] as = cells;\n        long max = base;\n        base = Long.MIN_VALUE;\n        if (as != null) {\n            int n = as.length;\n            for (int i = 0; i < n; ++i) {\n                Cell a = as[i];\n                if (a != null) {\n                    long v = a.value;\n                    a.value = Long.MIN_VALUE;\n                    if (v > max)\n                        max = v;\n                }\n            }\n        }\n        return max;\n    }\n\n    /**\n     * Returns the String representation of the {@link #max}.\n     * @return the String representation of the {@link #max}\n     */\n    public String toString() {\n        return Long.toString(max());\n    }\n\n    /**\n     * Equivalent to {@link #max}.\n     *\n     * @return the maximum\n     */\n    public long longValue() {\n        return max();\n    }\n\n    /**\n     * Returns the {@link #max} as an {@code int} after a narrowing\n     * primitive conversion.\n     */\n    public int intValue() {\n        return (int)max();\n    }\n\n    /**\n     * Returns the {@link #max} as a {@code float}\n     * after a widening primitive conversion.\n     */\n    public float floatValue() {\n        return (float)max();\n    }\n\n    /**\n     * Returns the {@link #max} as a {@code double} after a widening\n     * primitive conversion.\n     */\n    public double doubleValue() {\n        return (double)max();\n    }\n\n    private void writeObject(java.io.ObjectOutputStream s)\n        throws java.io.IOException {\n        s.defaultWriteObject();\n        s.writeLong(max());\n    }\n\n    private void readObject(ObjectInputStream s)\n        throws IOException, ClassNotFoundException {\n        s.defaultReadObject();\n        busy = 0;\n        cells = null;\n        base = s.readLong();\n    }\n\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/PlatformSpecific.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.concurrent.ThreadFactory;\n\npublic class PlatformSpecific {\n    private final Platform platform;\n\n    private enum Platform {\n        STANDARD, APPENGINE_STANDARD, APPENGINE_FLEXIBLE\n    }\n\n    private static PlatformSpecific INSTANCE = new PlatformSpecific();\n\n    private PlatformSpecific() {\n        platform = determinePlatformReflectively();\n    }\n\n    public static boolean isAppEngineStandardEnvironment() {\n        return INSTANCE.platform == Platform.APPENGINE_STANDARD;\n    }\n\n    public static boolean isAppEngine() {\n        return INSTANCE.platform == Platform.APPENGINE_FLEXIBLE || INSTANCE.platform == Platform.APPENGINE_STANDARD;\n    }\n\n    /*\n     * This detection mechanism is from Guava - specifically\n     * http://docs.guava-libraries.googlecode.com/git/javadoc/src-html/com/google/common/util/concurrent/MoreExecutors.html#line.766\n     * Added GAE_LONG_APP_ID check to detect only AppEngine Standard Environment\n     */\n    private static Platform determinePlatformReflectively() {\n        if (System.getProperty(\"com.google.appengine.runtime.environment\") == null) {\n            return Platform.STANDARD;\n        }\n        // GAE_LONG_APP_ID is only set in the GAE Flexible Environment, where we want standard threading\n        if (System.getenv(\"GAE_LONG_APP_ID\") != null) {\n            return Platform.APPENGINE_FLEXIBLE;\n        }\n        try {\n            // If the current environment is null, we're not inside AppEngine.\n            boolean isInsideAppengine = Class.forName(\"com.google.apphosting.api.ApiProxy\")\n                    .getMethod(\"getCurrentEnvironment\")\n                    .invoke(null) != null;\n            return isInsideAppengine ? Platform.APPENGINE_STANDARD : Platform.STANDARD;\n        } catch (ClassNotFoundException e) {\n            // If ApiProxy doesn't exist, we're not on AppEngine at all.\n            return Platform.STANDARD;\n        } catch (InvocationTargetException e) {\n            // If ApiProxy throws an exception, we're not in a proper AppEngine environment.\n            return Platform.STANDARD;\n        } catch (IllegalAccessException e) {\n            // If the method isn't accessible, we're not on a supported version of AppEngine;\n            return Platform.STANDARD;\n        } catch (NoSuchMethodException e) {\n            // If the method doesn't exist, we're not on a supported version of AppEngine;\n            return Platform.STANDARD;\n        }\n    }\n\n    public static ThreadFactory getAppEngineThreadFactory() {\n        try {\n            return (ThreadFactory) Class.forName(\"com.google.appengine.api.ThreadManager\")\n                    .getMethod(\"currentRequestThreadFactory\")\n                    .invoke(null);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(\"Couldn't invoke ThreadManager.currentRequestThreadFactory\", e);\n        } catch (ClassNotFoundException e) {\n            throw new RuntimeException(\"Couldn't invoke ThreadManager.currentRequestThreadFactory\", e);\n        } catch (NoSuchMethodException e) {\n            throw new RuntimeException(\"Couldn't invoke ThreadManager.currentRequestThreadFactory\", e);\n        } catch (InvocationTargetException e) {\n            throw new RuntimeException(e.getCause());\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/Striped64.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\n/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/publicdomain/zero/1.0/\n * \n * From http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/\n */\n\nimport java.util.Random;\n\n/**\n * A package-local class holding common representation and mechanics\n * for classes supporting dynamic striping on 64bit values. The class\n * extends Number so that concrete subclasses must publicly do so.\n */\nabstract class Striped64 extends Number {\n    /*\n     * This class maintains a lazily-initialized table of atomically\n     * updated variables, plus an extra \"base\" field. The table size\n     * is a power of two. Indexing uses masked per-thread hash codes.\n     * Nearly all declarations in this class are package-private,\n     * accessed directly by subclasses.\n     *\n     * Table entries are of class Cell; a variant of AtomicLong padded\n     * to reduce cache contention on most processors. Padding is\n     * overkill for most Atomics because they are usually irregularly\n     * scattered in memory and thus don't interfere much with each\n     * other. But Atomic objects residing in arrays will tend to be\n     * placed adjacent to each other, and so will most often share\n     * cache lines (with a huge negative performance impact) without\n     * this precaution.\n     *\n     * In part because Cells are relatively large, we avoid creating\n     * them until they are needed.  When there is no contention, all\n     * updates are made to the base field.  Upon first contention (a\n     * failed CAS on base update), the table is initialized to size 2.\n     * The table size is doubled upon further contention until\n     * reaching the nearest power of two greater than or equal to the\n     * number of CPUS. Table slots remain empty (null) until they are\n     * needed.\n     *\n     * A single spinlock (\"busy\") is used for initializing and\n     * resizing the table, as well as populating slots with new Cells.\n     * There is no need for a blocking lock: When the lock is not\n     * available, threads try other slots (or the base).  During these\n     * retries, there is increased contention and reduced locality,\n     * which is still better than alternatives.\n     *\n     * Per-thread hash codes are initialized to random values.\n     * Contention and/or table collisions are indicated by failed\n     * CASes when performing an update operation (see method\n     * retryUpdate). Upon a collision, if the table size is less than\n     * the capacity, it is doubled in size unless some other thread\n     * holds the lock. If a hashed slot is empty, and lock is\n     * available, a new Cell is created. Otherwise, if the slot\n     * exists, a CAS is tried.  Retries proceed by \"double hashing\",\n     * using a secondary hash (Marsaglia XorShift) to try to find a\n     * free slot.\n     *\n     * The table size is capped because, when there are more threads\n     * than CPUs, supposing that each thread were bound to a CPU,\n     * there would exist a perfect hash function mapping threads to\n     * slots that eliminates collisions. When we reach capacity, we\n     * search for this mapping by randomly varying the hash codes of\n     * colliding threads.  Because search is random, and collisions\n     * only become known via CAS failures, convergence can be slow,\n     * and because threads are typically not bound to CPUS forever,\n     * may not occur at all. However, despite these limitations,\n     * observed contention rates are typically low in these cases.\n     *\n     * It is possible for a Cell to become unused when threads that\n     * once hashed to it terminate, as well as in the case where\n     * doubling the table causes no thread to hash to it under\n     * expanded mask.  We do not try to detect or remove such cells,\n     * under the assumption that for long-running instances, observed\n     * contention levels will recur, so the cells will eventually be\n     * needed again; and for short-lived ones, it does not matter.\n     */\n\n    private static final long serialVersionUID = -3403386352761423917L;\n\n    /**\n     * Padded variant of AtomicLong supporting only raw accesses plus CAS.\n     * The value field is placed between pads, hoping that the JVM doesn't\n     * reorder them.\n     *\n     * JVM intrinsics note: It would be possible to use a release-only\n     * form of CAS here, if it were provided.\n     */\n    static final class Cell {\n        volatile long p0, p1, p2, p3, p4, p5, p6;\n        volatile long value;\n        volatile long q0, q1, q2, q3, q4, q5, q6;\n        Cell(long x) { value = x; }\n\n        final boolean cas(long cmp, long val) {\n            return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);\n        }\n\n        // Unsafe mechanics\n        private static final sun.misc.Unsafe UNSAFE;\n        private static final long valueOffset;\n        static {\n            try {\n                UNSAFE = getUnsafe();\n                Class<?> ak = Cell.class;\n                valueOffset = UNSAFE.objectFieldOffset\n                    (ak.getDeclaredField(\"value\"));\n            } catch (Exception e) {\n                throw new Error(e);\n            }\n        }\n\n    }\n\n    /**\n     * Holder for the thread-local hash code. The code is initially\n     * random, but may be set to a different value upon collisions.\n     */\n    static final class HashCode {\n        static final Random rng = new Random();\n        int code;\n        HashCode() {\n            int h = rng.nextInt(); // Avoid zero to allow xorShift rehash\n            code = (h == 0) ? 1 : h;\n        }\n    }\n\n    /**\n     * The corresponding ThreadLocal class\n     */\n    static final class ThreadHashCode extends ThreadLocal<HashCode> {\n        public HashCode initialValue() { return new HashCode(); }\n    }\n\n    /**\n     * Static per-thread hash codes. Shared across all instances to\n     * reduce ThreadLocal pollution and because adjustments due to\n     * collisions in one table are likely to be appropriate for\n     * others.\n     */\n    static final ThreadHashCode threadHashCode = new ThreadHashCode();\n\n    /** Number of CPUS, to place bound on table size */\n    static final int NCPU = Runtime.getRuntime().availableProcessors();\n\n    /**\n     * Table of cells. When non-null, size is a power of 2.\n     */\n    transient volatile Cell[] cells;\n\n    /**\n     * Base value, used mainly when there is no contention, but also as\n     * a fallback during table initialization races. Updated via CAS.\n     */\n    transient volatile long base;\n\n    /**\n     * Spinlock (locked via CAS) used when resizing and/or creating Cells.\n     */\n    transient volatile int busy;\n\n    /**\n     * Package-private default constructor\n     */\n    Striped64() {\n    }\n\n    /**\n     * CASes the base field.\n     */\n    final boolean casBase(long cmp, long val) {\n        return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val);\n    }\n\n    /**\n     * CASes the busy field from 0 to 1 to acquire lock.\n     */\n    final boolean casBusy() {\n        return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1);\n    }\n\n    /**\n     * Computes the function of current and new value. Subclasses\n     * should open-code this update function for most uses, but the\n     * virtualized form is needed within retryUpdate.\n     *\n     * @param currentValue the current value (of either base or a cell)\n     * @param newValue the argument from a user update call\n     * @return result of the update function\n     */\n    abstract long fn(long currentValue, long newValue);\n\n    /**\n     * Handles cases of updates involving initialization, resizing,\n     * creating new Cells, and/or contention. See above for\n     * explanation. This method suffers the usual non-modularity\n     * problems of optimistic retry code, relying on rechecked sets of\n     * reads.\n     *\n     * @param x the value\n     * @param hc the hash code holder\n     * @param wasUncontended false if CAS failed before call\n     */\n    final void retryUpdate(long x, HashCode hc, boolean wasUncontended) {\n        int h = hc.code;\n        boolean collide = false;                // True if last slot nonempty\n        for (;;) {\n            Cell[] as; Cell a; int n; long v;\n            if ((as = cells) != null && (n = as.length) > 0) {\n                if ((a = as[(n - 1) & h]) == null) {\n                    if (busy == 0) {            // Try to attach new Cell\n                        Cell r = new Cell(x);   // Optimistically create\n                        if (busy == 0 && casBusy()) {\n                            boolean created = false;\n                            try {               // Recheck under lock\n                                Cell[] rs; int m, j;\n                                if ((rs = cells) != null &&\n                                    (m = rs.length) > 0 &&\n                                    rs[j = (m - 1) & h] == null) {\n                                    rs[j] = r;\n                                    created = true;\n                                }\n                            } finally {\n                                busy = 0;\n                            }\n                            if (created)\n                                break;\n                            continue;           // Slot is now non-empty\n                        }\n                    }\n                    collide = false;\n                }\n                else if (!wasUncontended)       // CAS already known to fail\n                    wasUncontended = true;      // Continue after rehash\n                else if (a.cas(v = a.value, fn(v, x)))\n                    break;\n                else if (n >= NCPU || cells != as)\n                    collide = false;            // At max size or stale\n                else if (!collide)\n                    collide = true;\n                else if (busy == 0 && casBusy()) {\n                    try {\n                        if (cells == as) {      // Expand table unless stale\n                            Cell[] rs = new Cell[n << 1];\n                            for (int i = 0; i < n; ++i)\n                                rs[i] = as[i];\n                            cells = rs;\n                        }\n                    } finally {\n                        busy = 0;\n                    }\n                    collide = false;\n                    continue;                   // Retry with expanded table\n                }\n                h ^= h << 13;                   // Rehash\n                h ^= h >>> 17;\n                h ^= h << 5;\n            }\n            else if (busy == 0 && cells == as && casBusy()) {\n                boolean init = false;\n                try {                           // Initialize table\n                    if (cells == as) {\n                        Cell[] rs = new Cell[2];\n                        rs[h & 1] = new Cell(x);\n                        cells = rs;\n                        init = true;\n                    }\n                } finally {\n                    busy = 0;\n                }\n                if (init)\n                    break;\n            }\n            else if (casBase(v = base, fn(v, x)))\n                break;                          // Fall back on using base\n        }\n        hc.code = h;                            // Record index for next time\n    }\n\n\n    /**\n     * Sets base and all cells to the given value.\n     */\n    final void internalReset(long initialValue) {\n        Cell[] as = cells;\n        base = initialValue;\n        if (as != null) {\n            int n = as.length;\n            for (int i = 0; i < n; ++i) {\n                Cell a = as[i];\n                if (a != null)\n                    a.value = initialValue;\n            }\n        }\n    }\n\n    // Unsafe mechanics\n    private static final sun.misc.Unsafe UNSAFE;\n    private static final long baseOffset;\n    private static final long busyOffset;\n    static {\n        try {\n            UNSAFE = getUnsafe();\n            Class<?> sk = Striped64.class;\n            baseOffset = UNSAFE.objectFieldOffset\n                (sk.getDeclaredField(\"base\"));\n            busyOffset = UNSAFE.objectFieldOffset\n                (sk.getDeclaredField(\"busy\"));\n        } catch (Exception e) {\n            throw new Error(e);\n        }\n    }\n\n    /**\n     * Returns a sun.misc.Unsafe.  Suitable for use in a 3rd party package.\n     * Replace with a simple call to Unsafe.getUnsafe when integrating\n     * into a jdk.\n     *\n     * @return a sun.misc.Unsafe\n     */\n    private static sun.misc.Unsafe getUnsafe() {\n        try {\n            return sun.misc.Unsafe.getUnsafe();\n        } catch (SecurityException se) {\n            try {\n                return java.security.AccessController.doPrivileged\n                    (new java.security\n                     .PrivilegedExceptionAction<sun.misc.Unsafe>() {\n                        public sun.misc.Unsafe run() throws Exception {\n                            java.lang.reflect.Field f = sun.misc\n                                .Unsafe.class.getDeclaredField(\"theUnsafe\");\n                            f.setAccessible(true);\n                            return (sun.misc.Unsafe) f.get(null);\n                        }});\n            } catch (java.security.PrivilegedActionException e) {\n                throw new RuntimeException(\"Could not initialize intrinsics\",\n                                           e.getCause());\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "hystrix-core/src/main/java/com/netflix/hystrix/util/package-info.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * Common utility classes.\n * \n * @since 1.0.0\n */\npackage com.netflix.hystrix.util;"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/AbstractTestHystrixCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\n\npublic interface AbstractTestHystrixCommand<R> extends HystrixObservable<R>, InspectableBuilder {\n\n    enum ExecutionResult {\n        SUCCESS, FAILURE, ASYNC_FAILURE, HYSTRIX_FAILURE, NOT_WRAPPED_FAILURE, ASYNC_HYSTRIX_FAILURE, RECOVERABLE_ERROR, ASYNC_RECOVERABLE_ERROR, UNRECOVERABLE_ERROR, ASYNC_UNRECOVERABLE_ERROR, BAD_REQUEST, ASYNC_BAD_REQUEST, BAD_REQUEST_NOT_WRAPPED, MULTIPLE_EMITS_THEN_SUCCESS, MULTIPLE_EMITS_THEN_FAILURE, NO_EMITS_THEN_SUCCESS\n    }\n\n    enum FallbackResult {\n        UNIMPLEMENTED, SUCCESS, FAILURE, ASYNC_FAILURE, MULTIPLE_EMITS_THEN_SUCCESS, MULTIPLE_EMITS_THEN_FAILURE, NO_EMITS_THEN_SUCCESS\n    }\n\n    enum CacheEnabled {\n        YES, NO\n    }\n\n    HystrixPropertiesStrategy TEST_PROPERTIES_FACTORY = new TestPropertiesFactory();\n\n    class TestPropertiesFactory extends HystrixPropertiesStrategy {\n\n        @Override\n        public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {\n            if (builder == null) {\n                builder = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter();\n            }\n            return HystrixCommandPropertiesTest.asMock(builder);\n        }\n\n        @Override\n        public HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) {\n            if (builder == null) {\n                builder = HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder();\n            }\n            return HystrixThreadPoolPropertiesTest.asMock(builder);\n        }\n\n        @Override\n        public HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) {\n            throw new IllegalStateException(\"not expecting collapser properties\");\n        }\n\n        @Override\n        public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) {\n            return null;\n        }\n\n        @Override\n        public String getThreadPoolPropertiesCacheKey(HystrixThreadPoolKey threadPoolKey, com.netflix.hystrix.HystrixThreadPoolProperties.Setter builder) {\n            return null;\n        }\n\n        @Override\n        public String getCollapserPropertiesCacheKey(HystrixCollapserKey collapserKey, com.netflix.hystrix.HystrixCollapserProperties.Setter builder) {\n            return null;\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/CommonHystrixCommandTests.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.AbstractTestHystrixCommand.CacheEnabled;\nimport com.netflix.hystrix.AbstractTestHystrixCommand.ExecutionResult;\nimport com.netflix.hystrix.AbstractTestHystrixCommand.FallbackResult;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.Subscriber;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport static org.junit.Assert.*;\n\n/**\n * Place to share code and tests between {@link HystrixCommandTest} and {@link HystrixObservableCommandTest}.\n * @param <C>\n */\npublic abstract class CommonHystrixCommandTests<C extends AbstractTestHystrixCommand<Integer>> {\n\n    /**\n     * Run the command in multiple modes and check that the hook assertions hold in each and that the command succeeds\n     * @param ctor {@link AbstractTestHystrixCommand} constructor\n     * @param assertion sequence of assertions to check after the command has completed\n     */\n    abstract void assertHooksOnSuccess(Func0<C> ctor, Action1<C> assertion);\n\n    /**\n     * Run the command in multiple modes and check that the hook assertions hold in each and that the command fails\n     * @param ctor {@link AbstractTestHystrixCommand} constructor\n     * @param assertion sequence of assertions to check after the command has completed\n     */\n    abstract void assertHooksOnFailure(Func0<C> ctor, Action1<C> assertion);\n\n    /**\n     * Run the command in multiple modes and check that the hook assertions hold in each and that the command fails\n     * @param ctor {@link AbstractTestHystrixCommand} constructor\n     * @param assertion sequence of assertions to check after the command has completed\n     */\n    abstract void assertHooksOnFailure(Func0<C> ctor, Action1<C> assertion, boolean failFast);\n\n    /**\n     * Run the command in multiple modes and check that the hook assertions hold in each and that the command fails as soon as possible\n     * @param ctor {@link AbstractTestHystrixCommand} constructor\n     * @param assertion sequence of assertions to check after the command has completed\n     */\n    protected void assertHooksOnFailFast(Func0<C> ctor, Action1<C> assertion) {\n        assertHooksOnFailure(ctor, assertion, true);\n    }\n\n    /**\n     * Run the command via {@link com.netflix.hystrix.HystrixCommand#observe()}, immediately block and then assert\n     * @param command command to run\n     * @param assertion assertions to check\n     * @param isSuccess should the command succeed?\n     */\n    protected void assertBlockingObserve(C command, Action1<C> assertion, boolean isSuccess) {\n        System.out.println(\"Running command.observe(), immediately blocking and then running assertions...\");\n        if (isSuccess) {\n            try {\n                command.observe().toList().toBlocking().single();\n            } catch (Exception ex) {\n                throw new RuntimeException(ex);\n            }\n        } else {\n            try {\n                command.observe().toList().toBlocking().single();\n                fail(\"Expected a command failure!\");\n            } catch (Exception ex) {\n                System.out.println(\"Received expected ex : \" + ex);\n                ex.printStackTrace();\n            }\n        }\n\n        assertion.call(command);\n    }\n\n    /**\n     * Run the command via {@link com.netflix.hystrix.HystrixCommand#observe()}, let the {@link rx.Observable} terminal\n     * states unblock a {@link java.util.concurrent.CountDownLatch} and then assert\n     * @param command command to run\n     * @param assertion assertions to check\n     * @param isSuccess should the command succeed?\n     */\n    protected void assertNonBlockingObserve(C command, Action1<C> assertion, boolean isSuccess) {\n        System.out.println(\"Running command.observe(), awaiting terminal state of Observable, then running assertions...\");\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Integer> o = command.observe();\n\n        o.subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer i) {\n                //do nothing\n            }\n        });\n\n        try {\n            latch.await(3, TimeUnit.SECONDS);\n            assertion.call(command);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        if (isSuccess) {\n            try {\n                o.toList().toBlocking().single();\n            } catch (Exception ex) {\n                throw new RuntimeException(ex);\n            }\n        } else {\n            try {\n                o.toList().toBlocking().single();\n                fail(\"Expected a command failure!\");\n            } catch (Exception ex) {\n                System.out.println(\"Received expected ex : \" + ex);\n                ex.printStackTrace();\n            }\n        }\n    }\n\n    protected void assertSaneHystrixRequestLog(final int numCommands) {\n        HystrixRequestLog currentRequestLog = HystrixRequestLog.getCurrentRequest();\n\n        try {\n            assertEquals(numCommands, currentRequestLog.getAllExecutedCommands().size());\n            assertFalse(currentRequestLog.getExecutedCommandsAsString().contains(\"Executed\"));\n            assertTrue(currentRequestLog.getAllExecutedCommands().iterator().next().getExecutionEvents().size() >= 1);\n            //Most commands should have 1 execution event, but fallbacks / responses from cache can cause more than 1.  They should never have 0\n        } catch (Throwable ex) {\n            System.out.println(\"Problematic Request log : \" + currentRequestLog.getExecutedCommandsAsString() + \" , expected : \" + numCommands);\n            throw new RuntimeException(ex);\n        }\n    }\n\n    protected void assertCommandExecutionEvents(HystrixInvokableInfo<?> command, HystrixEventType... expectedEventTypes) {\n        boolean emitExpected = false;\n        int expectedEmitCount = 0;\n\n        boolean fallbackEmitExpected = false;\n        int expectedFallbackEmitCount = 0;\n\n        List<HystrixEventType> condensedEmitExpectedEventTypes = new ArrayList<HystrixEventType>();\n\n        for (HystrixEventType expectedEventType: expectedEventTypes) {\n            if (expectedEventType.equals(HystrixEventType.EMIT)) {\n                if (!emitExpected) {\n                    //first EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.EMIT);\n                }\n                emitExpected = true;\n                expectedEmitCount++;\n            } else if (expectedEventType.equals(HystrixEventType.FALLBACK_EMIT)) {\n                if (!fallbackEmitExpected) {\n                    //first FALLBACK_EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.FALLBACK_EMIT);\n                }\n                fallbackEmitExpected = true;\n                expectedFallbackEmitCount++;\n            } else {\n                condensedEmitExpectedEventTypes.add(expectedEventType);\n            }\n        }\n        List<HystrixEventType> actualEventTypes = command.getExecutionEvents();\n        assertEquals(expectedEmitCount, command.getNumberEmissions());\n        assertEquals(expectedFallbackEmitCount, command.getNumberFallbackEmissions());\n        assertEquals(condensedEmitExpectedEventTypes, actualEventTypes);\n    }\n\n    /**\n     * Threadpool with 1 thread, queue of size 1\n     */\n    protected static class SingleThreadedPoolWithQueue implements HystrixThreadPool {\n\n        final LinkedBlockingQueue<Runnable> queue;\n        final ThreadPoolExecutor pool;\n        private final int rejectionQueueSizeThreshold;\n\n        public SingleThreadedPoolWithQueue(int queueSize) {\n            this(queueSize, 100);\n        }\n\n        public SingleThreadedPoolWithQueue(int queueSize, int rejectionQueueSizeThreshold) {\n            queue = new LinkedBlockingQueue<Runnable>(queueSize);\n            pool = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, queue);\n            this.rejectionQueueSizeThreshold = rejectionQueueSizeThreshold;\n        }\n\n        @Override\n        public ThreadPoolExecutor getExecutor() {\n            return pool;\n        }\n\n        @Override\n        public Scheduler getScheduler() {\n            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);\n        }\n\n        @Override\n        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n        }\n\n        @Override\n        public void markThreadExecution() {\n            // not used for this test\n        }\n\n        @Override\n        public void markThreadCompletion() {\n            // not used for this test\n        }\n\n        @Override\n        public void markThreadRejection() {\n            // not used for this test\n        }\n\n        @Override\n        public boolean isQueueSpaceAvailable() {\n            return queue.size() < rejectionQueueSizeThreshold;\n        }\n\n    }\n\n    /**\n     * Threadpool with 1 thread, queue of size 1\n     */\n    protected static class SingleThreadedPoolWithNoQueue implements HystrixThreadPool {\n\n        final SynchronousQueue<Runnable> queue;\n        final ThreadPoolExecutor pool;\n\n        public SingleThreadedPoolWithNoQueue() {\n            queue = new SynchronousQueue<Runnable>();\n            pool = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, queue);\n        }\n\n        @Override\n        public ThreadPoolExecutor getExecutor() {\n            return pool;\n        }\n\n        @Override\n        public Scheduler getScheduler() {\n            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);\n        }\n\n        @Override\n        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n        }\n\n        @Override\n        public void markThreadExecution() {\n            // not used for this test\n        }\n\n        @Override\n        public void markThreadCompletion() {\n            // not used for this test\n        }\n\n        @Override\n        public void markThreadRejection() {\n            // not used for this test\n        }\n\n        @Override\n        public boolean isQueueSpaceAvailable() {\n            return true; //let the thread pool reject\n        }\n\n    }\n\n\n\n    /**\n     ********************* SEMAPHORE-ISOLATED Execution Hook Tests ***********************************\n     */\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : NO\n     * Execution Result: SUCCESS\n     */\n    @Test\n    public void testExecutionHookSemaphoreSuccess() {\n        assertHooksOnSuccess(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(1, 0, 1));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : NO\n     * Execution Result: synchronous HystrixBadRequestException\n     */\n    @Test\n    public void testExecutionHookSemaphoreBadRequestException() {\n        assertHooksOnFailure(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.BAD_REQUEST, FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(HystrixBadRequestException.class, hook.getCommandException().getClass());\n                        assertEquals(HystrixBadRequestException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookSemaphoreExceptionNoFallback() {\n        assertHooksOnFailure(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.FAILURE, FallbackResult.UNIMPLEMENTED);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookSemaphoreExceptionSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.FAILURE, FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookSemaphoreExceptionUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.FAILURE, FallbackResult.FAILURE);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : YES\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookSemaphoreRejectedNoFallback() {\n        assertHooksOnFailFast(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        AbstractCommand.TryableSemaphore semaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(2));\n\n                        final C cmd1 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.UNIMPLEMENTED, semaphore);\n                        final C cmd2 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.UNIMPLEMENTED, semaphore);\n\n                        //saturate the semaphore\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd1.observe();\n                            }\n                        }.start();\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd2.observe();\n                            }\n                        }.start();\n\n                        try {\n                            //give the saturating threads a chance to run before we run the command we want to get rejected\n                            Thread.sleep(200);\n                        } catch (InterruptedException ie) {\n                            throw new RuntimeException(ie);\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.UNIMPLEMENTED, semaphore);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : YES\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookSemaphoreRejectedSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        AbstractCommand.TryableSemaphore semaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(2));\n\n                        final C cmd1 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 1500, FallbackResult.SUCCESS, semaphore);\n                        final C cmd2 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 1500, FallbackResult.SUCCESS, semaphore);\n\n                        //saturate the semaphore\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd1.observe();\n                            }\n                        }.start();\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd2.observe();\n                            }\n                        }.start();\n\n                        try {\n                            //give the saturating threads a chance to run before we run the command we want to get rejected\n                            Thread.sleep(200);\n                        } catch (InterruptedException ie) {\n                            throw new RuntimeException(ie);\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.SUCCESS, semaphore);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(\"onStart - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reached? : YES\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookSemaphoreRejectedUnsuccessfulFallback() {\n        assertHooksOnFailFast(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        AbstractCommand.TryableSemaphore semaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(2));\n\n                        final C cmd1 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.FAILURE, semaphore);\n                        final C cmd2 = getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.FAILURE, semaphore);\n\n                        //saturate the semaphore\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd1.observe();\n                            }\n                        }.start();\n                        new Thread() {\n                            @Override\n                            public void run() {\n                                cmd2.observe();\n                            }\n                        }.start();\n\n                        try {\n                            //give the saturating threads a chance to run before we run the command we want to get rejected\n                            Thread.sleep(200);\n                        } catch (InterruptedException ie) {\n                            throw new RuntimeException(ie);\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.SEMAPHORE, ExecutionResult.SUCCESS, 500, FallbackResult.FAILURE, semaphore);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: SEMAPHORE\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookSemaphoreShortCircuitNoFallback() {\n        assertHooksOnFailFast(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.SEMAPHORE, FallbackResult.UNIMPLEMENTED);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: SEMAPHORE\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookSemaphoreShortCircuitSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.SEMAPHORE, FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(\"onStart - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: SEMAPHORE\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookSemaphoreShortCircuitUnsuccessfulFallback() {\n        assertHooksOnFailFast(\n                new Func0<C>() {\n                    @Override\n                    public C call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.SEMAPHORE, FallbackResult.FAILURE);\n                    }\n                },\n                new Action1<C>() {\n                    @Override\n                    public void call(C command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     ********************* END SEMAPHORE-ISOLATED Execution Hook Tests ***********************************\n     */\n\n    /**\n     * Abstract methods defining a way to instantiate each of the described commands.\n     * {@link HystrixCommandTest} and {@link HystrixObservableCommandTest} should each provide concrete impls for\n     * {@link HystrixCommand}s and {@link} HystrixObservableCommand}s, respectively.\n     */\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult) {\n        return getCommand(isolationStrategy, executionResult, FallbackResult.UNIMPLEMENTED);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, FallbackResult.UNIMPLEMENTED);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, FallbackResult fallbackResult) {\n        return getCommand(isolationStrategy, executionResult, 0, fallbackResult);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, (executionLatency * 2) + 200, CacheEnabled.NO, \"foo\", 10, 10);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int timeout) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, timeout, CacheEnabled.NO, \"foo\", 10, 10);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, int executionSemaphoreCount, int fallbackSemaphoreCount) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphoreCount, fallbackSemaphoreCount, false);\n    }\n\n    C getCommand(HystrixCommandKey key, ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, int executionSemaphoreCount, int fallbackSemaphoreCount) {\n        AbstractCommand.TryableSemaphoreActual executionSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(executionSemaphoreCount));\n        AbstractCommand.TryableSemaphoreActual fallbackSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(fallbackSemaphoreCount));\n\n        return getCommand(key, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, false);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, int executionSemaphoreCount, int fallbackSemaphoreCount, boolean circuitBreakerDisabled) {\n        AbstractCommand.TryableSemaphoreActual executionSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(executionSemaphoreCount));\n        AbstractCommand.TryableSemaphoreActual fallbackSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(fallbackSemaphoreCount));\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, int executionSemaphoreCount, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n        AbstractCommand.TryableSemaphoreActual executionSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(executionSemaphoreCount));\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    abstract C getCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, AbstractCommand.TryableSemaphore executionSemaphore, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled);\n\n    abstract C getCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, AbstractCommand.TryableSemaphore executionSemaphore, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled);\n\n    C getLatentCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int timeout) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, timeout, CacheEnabled.NO, \"foo\", 10, 10);\n    }\n\n    C getLatentCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout) {\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, 0, circuitBreaker, threadPool, timeout, CacheEnabled.NO, \"foo\", 10, 10);\n    }\n\n    C getLatentCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, AbstractCommand.TryableSemaphore executionSemaphore) {\n        AbstractCommand.TryableSemaphoreActual fallbackSemaphore = new AbstractCommand.TryableSemaphoreActual(HystrixProperty.Factory.asProperty(10));\n        return getCommand(isolationStrategy, executionResult, executionLatency, fallbackResult, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, (executionLatency * 2) + 200, CacheEnabled.NO, \"foo\", executionSemaphore, fallbackSemaphore, false);\n    }\n\n    C getCircuitOpenCommand(ExecutionIsolationStrategy isolationStrategy, FallbackResult fallbackResult) {\n        HystrixCircuitBreakerTest.TestCircuitBreaker openCircuit = new HystrixCircuitBreakerTest.TestCircuitBreaker().setForceShortCircuit(true);\n        return getCommand(isolationStrategy, ExecutionResult.SUCCESS, 0, fallbackResult, 0, openCircuit, null, 500, CacheEnabled.NO, \"foo\", 10, 10, false);\n    }\n\n    C getSharedCircuitBreakerCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, FallbackResult fallbackResult, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker) {\n        return getCommand(commandKey, isolationStrategy, ExecutionResult.FAILURE, 0, fallbackResult, 0, circuitBreaker, null, 500, CacheEnabled.NO, \"foo\", 10, 10);\n    }\n\n    C getCircuitBreakerDisabledCommand(ExecutionIsolationStrategy isolationStrategy, ExecutionResult executionResult) {\n        return getCommand(isolationStrategy, executionResult, 0, FallbackResult.UNIMPLEMENTED, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, 500, CacheEnabled.NO, \"foo\", 10, 10, true);\n    }\n\n    C getRecoverableErrorCommand(ExecutionIsolationStrategy isolationStrategy, FallbackResult fallbackResult) {\n        return getCommand(isolationStrategy, ExecutionResult.RECOVERABLE_ERROR, 0, fallbackResult);\n    }\n\n    C getUnrecoverableErrorCommand(ExecutionIsolationStrategy isolationStrategy, FallbackResult fallbackResult) {\n        return getCommand(isolationStrategy, ExecutionResult.UNRECOVERABLE_ERROR, 0, fallbackResult);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.Random;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker.HystrixCircuitBreakerImpl;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport rx.Observable;\nimport rx.Subscription;\n\n/**\n * These tests each use a different command key to ensure that running them in parallel doesn't allow the state\n * built up during a test to cause others to fail\n */\npublic class HystrixCircuitBreakerTest {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @Before\n    public void init() {\n        for (HystrixCommandMetrics metricsInstance: HystrixCommandMetrics.getInstances()) {\n            metricsInstance.resetStream();\n        }\n\n        HystrixCommandMetrics.reset();\n        HystrixCircuitBreaker.Factory.reset();\n        Hystrix.reset();\n    }\n\n    /**\n     * A simple circuit breaker intended for unit testing of the {@link HystrixCommand} object, NOT production use.\n     * <p>\n     * This uses simple logic to 'trip' the circuit after 3 subsequent failures and doesn't recover.\n     */\n    public static class TestCircuitBreaker implements HystrixCircuitBreaker {\n\n        final HystrixCommandMetrics metrics;\n        private boolean forceShortCircuit = false;\n\n        public TestCircuitBreaker() {\n            this.metrics = getMetrics(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter());\n            forceShortCircuit = false;\n        }\n\n        public TestCircuitBreaker(HystrixCommandKey commandKey) {\n            this.metrics = getMetrics(commandKey, HystrixCommandPropertiesTest.getUnitTestPropertiesSetter());\n            forceShortCircuit = false;\n        }\n\n        public TestCircuitBreaker setForceShortCircuit(boolean value) {\n            this.forceShortCircuit = value;\n            return this;\n        }\n\n        @Override\n        public boolean isOpen() {\n            System.out.println(\"metrics : \" + metrics.getCommandKey().name() + \" : \" + metrics.getHealthCounts());\n            if (forceShortCircuit) {\n                return true;\n            } else {\n                return metrics.getHealthCounts().getErrorCount() >= 3;\n            }\n        }\n\n        @Override\n        public void markSuccess() {\n            // we don't need to do anything since we're going to permanently trip the circuit\n        }\n\n        @Override\n        public void markNonSuccess() {\n\n        }\n\n        @Override\n        public boolean attemptExecution() {\n            return !isOpen();\n        }\n\n        @Override\n        public boolean allowRequest() {\n            return !isOpen();\n        }\n\n    }\n\n\n    /**\n     * Test that if all 'marks' are successes during the test window that it does NOT trip the circuit.\n     * Test that if all 'marks' are failures during the test window that it trips the circuit.\n     */\n    @Test\n    public void testTripCircuit() {\n        String key = \"cmd-A\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd3 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);\n\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            cmd1.execute();\n            cmd2.execute();\n            cmd3.execute();\n            cmd4.execute();\n\n            // this should still allow requests as everything has been successful\n            Thread.sleep(100);\n            //assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            // fail\n            HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 1);\n            HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 1);\n            HystrixCommand<Boolean> cmd7 = new FailureCommand(key, 1);\n            HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);\n            cmd5.execute();\n            cmd6.execute();\n            cmd7.execute();\n            cmd8.execute();\n\n            // everything has failed in the test window so we should return false now\n            Thread.sleep(100);\n            assertFalse(cb.allowRequest());\n            assertTrue(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that if the % of failures is higher than the threshold that the circuit trips.\n     */\n    @Test\n    public void testTripCircuitOnFailuresAboveThreshold() {\n        String key = \"cmd-B\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            // success with high latency\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);\n            cmd4.execute();\n            HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 1);\n            cmd5.execute();\n            HystrixCommand<Boolean> cmd6 = new SuccessCommand(key, 1);\n            cmd6.execute();\n            HystrixCommand<Boolean> cmd7 = new FailureCommand(key, 1);\n            cmd7.execute();\n            HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);\n            cmd8.execute();\n\n            // this should trip the circuit as the error percentage is above the threshold\n            Thread.sleep(100);\n            assertFalse(cb.allowRequest());\n            assertTrue(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that if the % of failures is higher than the threshold that the circuit trips.\n     */\n    @Test\n    public void testCircuitDoesNotTripOnFailuresBelowThreshold() {\n        String key = \"cmd-C\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            // success with high latency\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);\n            cmd4.execute();\n            HystrixCommand<Boolean> cmd5 = new SuccessCommand(key, 1);\n            cmd5.execute();\n            HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 1);\n            cmd6.execute();\n            HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 1);\n            cmd7.execute();\n            HystrixCommand<Boolean> cmd8 = new FailureCommand(key, 1);\n            cmd8.execute();\n\n            // this should remain closed as the failure threshold is below the percentage limit\n            Thread.sleep(100);\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            System.out.println(\"Current CircuitBreaker Status : \" + cmd1.getMetrics().getHealthCounts());\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that if all 'marks' are timeouts that it will trip the circuit.\n     */\n    @Test\n    public void testTripCircuitOnTimeouts() {\n        String key = \"cmd-D\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new TimeoutCommand(key);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            // success with high latency\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new TimeoutCommand(key);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new TimeoutCommand(key);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key);\n            cmd4.execute();\n\n            // everything has been a timeout so we should not allow any requests\n            Thread.sleep(100);\n            assertFalse(cb.allowRequest());\n            assertTrue(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that if the % of timeouts is higher than the threshold that the circuit trips.\n     */\n    @Test\n    public void testTripCircuitOnTimeoutsAboveThreshold() {\n        String key = \"cmd-E\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 60);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            // success with high latency\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new SuccessCommand(key, 1);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new TimeoutCommand(key);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);\n            cmd4.execute();\n            HystrixCommand<Boolean> cmd5 = new TimeoutCommand(key);\n            cmd5.execute();\n            HystrixCommand<Boolean> cmd6 = new TimeoutCommand(key);\n            cmd6.execute();\n            HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 1);\n            cmd7.execute();\n            HystrixCommand<Boolean> cmd8 = new TimeoutCommand(key);\n            cmd8.execute();\n            HystrixCommand<Boolean> cmd9 = new TimeoutCommand(key);\n            cmd9.execute();\n\n            // this should trip the circuit as the error percentage is above the threshold\n            Thread.sleep(100);\n            assertTrue(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that on an open circuit that a single attempt will be allowed after a window of time to see if issues are resolved.\n     */\n    @Test\n    public void testSingleTestOnOpenCircuitAfterTimeWindow() {\n        String key = \"cmd-F\";\n        try {\n            int sleepWindow = 200;\n            HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new FailureCommand(key, 1);\n            cmd4.execute();\n\n            // everything has failed in the test window so we should return false now\n            Thread.sleep(100);\n            assertFalse(cb.allowRequest());\n            assertTrue(cb.isOpen());\n\n            // wait for sleepWindow to pass\n            Thread.sleep(sleepWindow + 50);\n\n            // we should now allow 1 request\n            assertTrue(cb.attemptExecution());\n            // but the circuit should still be open\n            assertTrue(cb.isOpen());\n            // and further requests are still blocked\n            assertFalse(cb.attemptExecution());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Test that an open circuit is closed after 1 success.  This also ensures that the rolling window (containing failures) is cleared after the sleep window\n     * Otherwise, the next bucket roll would produce another signal to fail unless it is explicitly cleared (via {@link HystrixCommandMetrics#resetStream()}.\n     */\n    @Test\n    public void testCircuitClosedAfterSuccess() {\n        String key = \"cmd-G\";\n        try {\n            int sleepWindow = 100;\n            HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 1, sleepWindow);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1, sleepWindow);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1, sleepWindow);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key, sleepWindow);\n            cmd4.execute();\n\n            // everything has failed in the test window so we should return false now\n            Thread.sleep(100);\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            System.out.println(\"CircuitBreaker state 1 : \" + cmd1.getMetrics().getHealthCounts());\n            assertTrue(cb.isOpen());\n\n            // wait for sleepWindow to pass\n            Thread.sleep(sleepWindow + 50);\n\n            // but the circuit should still be open\n            assertTrue(cb.isOpen());\n\n            // we should now allow 1 request, and upon success, should cause the circuit to be closed\n            HystrixCommand<Boolean> cmd5 = new SuccessCommand(key, 60, sleepWindow);\n            Observable<Boolean> asyncResult = cmd5.observe();\n\n            // and further requests are still blocked while the singleTest command is in flight\n            assertFalse(cb.allowRequest());\n\n            asyncResult.toBlocking().single();\n\n            // all requests should be open again\n\n            Thread.sleep(100);\n            System.out.println(\"CircuitBreaker state 2 : \" + cmd1.getMetrics().getHealthCounts());\n            assertTrue(cb.allowRequest());\n            assertTrue(cb.allowRequest());\n            assertTrue(cb.allowRequest());\n            // and the circuit should be closed again\n            assertFalse(cb.isOpen());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Over a period of several 'windows' a single attempt will be made and fail and then finally succeed and close the circuit.\n     * <p>\n     * Ensure the circuit is kept open through the entire testing period and that only the single attempt in each window is made.\n     */\n    @Test\n    public void testMultipleTimeWindowRetriesBeforeClosingCircuit() {\n        String key = \"cmd-H\";\n        try {\n            int sleepWindow = 200;\n            HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new TimeoutCommand(key);\n            cmd4.execute();\n\n            // everything has failed in the test window so we should return false now\n            System.out.println(\"!!!! 1: 4 failures, circuit will open on recalc\");\n            Thread.sleep(100);\n\n            assertTrue(cb.isOpen());\n\n            // wait for sleepWindow to pass\n            System.out.println(\"!!!! 2: Sleep window starting where all commands fail-fast\");\n            Thread.sleep(sleepWindow + 50);\n            System.out.println(\"!!!! 3: Sleep window over, should allow singleTest()\");\n\n            // but the circuit should still be open\n            assertTrue(cb.isOpen());\n\n            // we should now allow 1 request, and upon failure, should not affect the circuit breaker, which should remain open\n            HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 60);\n            Observable<Boolean> asyncResult5 = cmd5.observe();\n            System.out.println(\"!!!! 4: Kicked off the single-test\");\n\n            // and further requests are still blocked while the singleTest command is in flight\n            assertFalse(cb.allowRequest());\n            System.out.println(\"!!!! 5: Confirmed that no other requests go out during single-test\");\n\n            asyncResult5.toBlocking().single();\n            System.out.println(\"!!!! 6: SingleTest just completed\");\n\n            // all requests should still be blocked, because the singleTest failed\n            assertFalse(cb.allowRequest());\n            assertFalse(cb.allowRequest());\n            assertFalse(cb.allowRequest());\n\n            // wait for sleepWindow to pass\n            System.out.println(\"!!!! 2nd sleep window START\");\n            Thread.sleep(sleepWindow + 50);\n            System.out.println(\"!!!! 2nd sleep window over\");\n\n            // we should now allow 1 request, and upon failure, should not affect the circuit breaker, which should remain open\n            HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 60);\n            Observable<Boolean> asyncResult6 = cmd6.observe();\n            System.out.println(\"2nd singleTest just kicked off\");\n\n            //and further requests are still blocked while the singleTest command is in flight\n            assertFalse(cb.allowRequest());\n            System.out.println(\"confirmed that 2nd singletest only happened once\");\n\n            asyncResult6.toBlocking().single();\n            System.out.println(\"2nd singleTest now over\");\n\n            // all requests should still be blocked, because the singleTest failed\n            assertFalse(cb.allowRequest());\n            assertFalse(cb.allowRequest());\n            assertFalse(cb.allowRequest());\n\n            // wait for sleepWindow to pass\n            Thread.sleep(sleepWindow + 50);\n\n            // but the circuit should still be open\n            assertTrue(cb.isOpen());\n\n            // we should now allow 1 request, and upon success, should cause the circuit to be closed\n            HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 60);\n            Observable<Boolean> asyncResult7 = cmd7.observe();\n\n            // and further requests are still blocked while the singleTest command is in flight\n            assertFalse(cb.allowRequest());\n\n            asyncResult7.toBlocking().single();\n\n            // all requests should be open again\n            assertTrue(cb.allowRequest());\n            assertTrue(cb.allowRequest());\n            assertTrue(cb.allowRequest());\n            // and the circuit should be closed again\n            assertFalse(cb.isOpen());\n\n            // and the circuit should be closed again\n            assertFalse(cb.isOpen());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * When volume of reporting during a statistical window is lower than a defined threshold the circuit\n     * will not trip regardless of whatever statistics are calculated.\n     */\n    @Test\n    public void testLowVolumeDoesNotTripCircuit() {\n        String key = \"cmd-I\";\n        try {\n            int sleepWindow = 200;\n            int lowVolume = 5;\n\n            HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 60, sleepWindow, lowVolume);\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // this should start as allowing requests\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n            cmd1.execute();\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1, sleepWindow, lowVolume);\n            cmd2.execute();\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1, sleepWindow, lowVolume);\n            cmd3.execute();\n            HystrixCommand<Boolean> cmd4 = new FailureCommand(key, 1, sleepWindow, lowVolume);\n            cmd4.execute();\n\n            // even though it has all failed we won't trip the circuit because the volume is low\n            Thread.sleep(100);\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUnsubscriptionDoesNotLeaveCircuitStuckHalfOpen() {\n        String key = \"cmd-J\";\n        try {\n            int sleepWindow = 200;\n\n            // fail\n            HystrixCommand<Boolean> cmd1 = new FailureCommand(key, 1, sleepWindow);\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1, sleepWindow);\n            HystrixCommand<Boolean> cmd3 = new FailureCommand(key, 1, sleepWindow);\n            HystrixCommand<Boolean> cmd4 = new FailureCommand(key, 1, sleepWindow);\n            cmd1.execute();\n            cmd2.execute();\n            cmd3.execute();\n            cmd4.execute();\n\n            HystrixCircuitBreaker cb = cmd1.circuitBreaker;\n\n            // everything has failed in the test window so we should return false now\n            Thread.sleep(100);\n            assertFalse(cb.allowRequest());\n            assertTrue(cb.isOpen());\n\n            //this should occur after the sleep window, so get executed\n            //however, it is unsubscribed, so never updates state on the circuit-breaker\n            HystrixCommand<Boolean> cmd5 = new SuccessCommand(key, 5000, sleepWindow);\n\n            //wait for sleep window to pass\n            Thread.sleep(sleepWindow + 50);\n\n            Observable<Boolean> o = cmd5.observe();\n            Subscription s = o.subscribe();\n            s.unsubscribe();\n\n            //wait for 10 sleep windows, then try a successful command.  this should return the circuit to CLOSED\n\n            Thread.sleep(10 * sleepWindow);\n            HystrixCommand<Boolean> cmd6 = new SuccessCommand(key, 1, sleepWindow);\n            cmd6.execute();\n\n            Thread.sleep(100);\n            assertTrue(cb.allowRequest());\n            assertFalse(cb.isOpen());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Utility method for creating {@link HystrixCommandMetrics} for unit tests.\n     */\n    private static HystrixCommandMetrics getMetrics(HystrixCommandProperties.Setter properties) {\n        return HystrixCommandMetrics.getInstance(CommandKeyForUnitTest.KEY_ONE, CommandOwnerForUnitTest.OWNER_ONE, ThreadPoolKeyForUnitTest.THREAD_POOL_ONE, HystrixCommandPropertiesTest.asMock(properties));\n    }\n\n\n    /**\n     * Utility method for creating {@link HystrixCommandMetrics} for unit tests.\n     */\n    private static HystrixCommandMetrics getMetrics(HystrixCommandKey commandKey, HystrixCommandProperties.Setter properties) {\n        return HystrixCommandMetrics.getInstance(commandKey, CommandOwnerForUnitTest.OWNER_ONE, ThreadPoolKeyForUnitTest.THREAD_POOL_ONE, HystrixCommandPropertiesTest.asMock(properties));\n    }\n\n    /**\n     * Utility method for creating {@link HystrixCircuitBreaker} for unit tests.\n     */\n    private static HystrixCircuitBreaker getCircuitBreaker(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandMetrics metrics, HystrixCommandProperties.Setter properties) {\n        return new HystrixCircuitBreakerImpl(key, commandGroup, HystrixCommandPropertiesTest.asMock(properties), metrics);\n    }\n\n    private static enum CommandOwnerForUnitTest implements HystrixCommandGroupKey {\n        OWNER_ONE, OWNER_TWO\n    }\n\n    private static enum ThreadPoolKeyForUnitTest implements HystrixThreadPoolKey {\n        THREAD_POOL_ONE, THREAD_POOL_TWO\n    }\n\n    private static enum CommandKeyForUnitTest implements HystrixCommandKey {\n        KEY_ONE, KEY_TWO\n    }\n\n    // ignoring since this never ends ... useful for testing https://github.com/Netflix/Hystrix/issues/236\n    @Ignore\n    @Test\n    public void testSuccessClosesCircuitWhenBusy() throws InterruptedException {\n        HystrixPlugins.getInstance().registerCommandExecutionHook(new MyHystrixCommandExecutionHook());\n        try {\n            performLoad(200, 0, 40);\n            performLoad(250, 100, 40);\n            performLoad(600, 0, 40);\n        } finally {\n            Hystrix.reset();\n        }\n\n    }\n\n    void performLoad(int totalNumCalls, int errPerc, int waitMillis) {\n\n        Random rnd = new Random();\n\n        for (int i = 0; i < totalNumCalls; i++) {\n            //System.out.println(i);\n\n            try {\n                boolean err = rnd.nextFloat() * 100 < errPerc;\n\n                TestCommand cmd = new TestCommand(err);\n                cmd.execute();\n\n            } catch (Exception e) {\n                //System.err.println(e.getMessage());\n            }\n\n            try {\n                Thread.sleep(waitMillis);\n            } catch (InterruptedException e) {\n            }\n        }\n    }\n\n    public class TestCommand extends HystrixCommand<String> {\n\n        boolean error;\n\n        public TestCommand(final boolean error) {\n            super(HystrixCommandGroupKey.Factory.asKey(\"group\"));\n\n            this.error = error;\n        }\n\n        @Override\n        protected String run() throws Exception {\n\n            if (error) {\n                throw new Exception(\"forced failure\");\n            } else {\n                return \"success\";\n            }\n        }\n\n        @Override\n        protected String getFallback() {\n            if (isFailedExecution()) {\n                return getFailedExecutionException().getMessage();\n            } else {\n                return \"other fail reason\";\n            }\n        }\n\n    }\n\n    private class Command extends HystrixCommand<Boolean> {\n\n        private final boolean shouldFail;\n        private final boolean shouldFailWithBadRequest;\n        private final long latencyToAdd;\n\n        public Command(String commandKey, boolean shouldFail, boolean shouldFailWithBadRequest, long latencyToAdd, int sleepWindow, int requestVolumeThreshold) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"Command\")).andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)).\n                    andCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().\n                            withExecutionTimeoutInMilliseconds(500).\n                            withCircuitBreakerRequestVolumeThreshold(requestVolumeThreshold).\n                            withCircuitBreakerSleepWindowInMilliseconds(sleepWindow)));\n            this.shouldFail = shouldFail;\n            this.shouldFailWithBadRequest = shouldFailWithBadRequest;\n            this.latencyToAdd = latencyToAdd;\n        }\n\n        public Command(String commandKey, boolean shouldFail, long latencyToAdd) {\n            this(commandKey, shouldFail, false, latencyToAdd, 200, 1);\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            Thread.sleep(latencyToAdd);\n            if (shouldFail) {\n                throw new RuntimeException(\"induced failure\");\n            }\n            if (shouldFailWithBadRequest) {\n                throw new HystrixBadRequestException(\"bad request\");\n            }\n            return true;\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n    }\n\n    private class SuccessCommand extends Command {\n\n        SuccessCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, false, latencyToAdd);\n        }\n\n        SuccessCommand(String commandKey, long latencyToAdd, int sleepWindow) {\n            super(commandKey, false, false, latencyToAdd, sleepWindow, 1);\n        }\n    }\n\n    private class FailureCommand extends Command {\n\n        FailureCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, true, latencyToAdd);\n        }\n\n        FailureCommand(String commandKey, long latencyToAdd, int sleepWindow) {\n            super(commandKey, true, false, latencyToAdd, sleepWindow, 1);\n        }\n\n        FailureCommand(String commandKey, long latencyToAdd, int sleepWindow, int requestVolumeThreshold) {\n            super(commandKey, true, false, latencyToAdd, sleepWindow, requestVolumeThreshold);\n        }\n    }\n\n    private class TimeoutCommand extends Command {\n\n        TimeoutCommand(String commandKey) {\n            super(commandKey, false, 2000);\n        }\n\n        TimeoutCommand(String commandKey, int sleepWindow) {\n            super(commandKey, false, false, 2000, sleepWindow, 1);\n        }\n    }\n\n    private class BadRequestCommand extends Command {\n        BadRequestCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, false, true, latencyToAdd, 200, 1);\n        }\n\n        BadRequestCommand(String commandKey, long latencyToAdd, int sleepWindow) {\n            super(commandKey, false, true, latencyToAdd, sleepWindow, 1);\n        }\n    }\n\n    public class MyHystrixCommandExecutionHook extends HystrixCommandExecutionHook {\n\n        @Override\n        public <T> T onComplete(final HystrixInvokable<T> command, final T response) {\n\n            logHC(command, response);\n\n            return super.onComplete(command, response);\n        }\n\n        private int counter = 0;\n\n        private <T> void logHC(HystrixInvokable<T> command, T response) {\n\n            if(command instanceof HystrixInvokableInfo) {\n                HystrixInvokableInfo<T> commandInfo = (HystrixInvokableInfo<T>)command;\n            HystrixCommandMetrics metrics = commandInfo.getMetrics();\n            System.out.println(\"cb/error-count/%/total: \"\n                    + commandInfo.isCircuitBreakerOpen() + \" \"\n                    + metrics.getHealthCounts().getErrorCount() + \" \"\n                    + metrics.getHealthCounts().getErrorPercentage() + \" \"\n                    + metrics.getHealthCounts().getTotalRequests() + \"  => \" + response + \"  \" + commandInfo.getExecutionEvents());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCollapserTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport java.lang.ref.Reference;\nimport java.lang.ref.SoftReference;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesCollapserDefault;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport com.netflix.hystrix.util.HystrixTimer;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.collapser.CollapserTimer;\nimport com.netflix.hystrix.collapser.RealCollapserTimer;\nimport com.netflix.hystrix.collapser.RequestCollapser;\nimport com.netflix.hystrix.collapser.RequestCollapserFactory;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableHolder;\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.observers.Subscribers;\nimport rx.observers.TestSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixCollapserTest {\n    @Rule\n    public HystrixRequestContextRule context = new HystrixRequestContextRule();\n\n    @Before\n    public void init() {\n        HystrixCollapserMetrics.reset();\n        HystrixCommandMetrics.reset();\n        HystrixPropertiesFactory.reset();\n    }\n\n    @Test\n    public void testTwoRequests() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Future<String> response1 = collapser1.queue();\n        HystrixCollapser<List<String>, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Future<String> response2 = collapser2.queue();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1\", response1.get());\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixCollapserMetrics metrics = collapser1.getMetrics();\n        assertSame(metrics, collapser2.getMetrics());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertEquals(2, command.getNumberCollapsed());\n    }\n\n    @Test\n    public void testMultipleBatches() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestRequestCollapser(timer, 2).queue();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n\n        // now request more\n        Future<String> response3 = new TestRequestCollapser(timer, 3).queue();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n\n        // we should have had it execute twice now\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testMaxRequestsInBatch() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1, 2, 10);\n        HystrixCollapser<List<String>, String, String> collapser2 = new TestRequestCollapser(timer, 2, 2, 10);\n        HystrixCollapser<List<String>, String, String> collapser3 = new TestRequestCollapser(timer, 3, 2, 10);\n        System.out.println(\"*** \" + System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Constructed the collapsers\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = collapser2.queue();\n        Future<String> response3 = collapser3.queue();\n        System.out.println(\"*** \" +System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" queued the collapsers\");\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n        System.out.println(\"*** \" +System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" incremented the virtual timer\");\n\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n\n        // we should have had it execute twice because the batch size was 2\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testRequestsOverTime() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Future<String> response1 = collapser1.queue();\n        timer.incrementTime(5);\n        Future<String> response2 = new TestRequestCollapser(timer, 2).queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response3 = new TestRequestCollapser(timer, 3).queue();\n        timer.incrementTime(6);\n        Future<String> response4 = new TestRequestCollapser(timer, 4).queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response5 = new TestRequestCollapser(timer, 5).queue();\n        timer.incrementTime(10);\n        // should execute here\n\n        // wait for all tasks to complete\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4\", response4.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"5\", response5.get(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    class Pair<A, B> {\n        final A a;\n        final B b;\n\n        Pair(A a, B b) {\n            this.a = a;\n            this.b = b;\n        }\n    }\n\n    class MyCommand extends HystrixCommand<List<Pair<String, Integer>>> {\n\n        private final List<String> args;\n\n        public MyCommand(List<String> args) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"BATCH\")));\n            this.args = args;\n        }\n\n        @Override\n        protected List<Pair<String, Integer>> run() throws Exception {\n            System.out.println(\"Executing batch command on : \" + Thread.currentThread().getName() + \" with args : \" + args);\n            List<Pair<String, Integer>> results = new ArrayList<Pair<String, Integer>>();\n            for (String arg: args) {\n                results.add(new Pair<String, Integer>(arg, Integer.parseInt(arg)));\n            }\n            return results;\n        }\n    }\n\n    class MyCollapser extends HystrixCollapser<List<Pair<String, Integer>>, Integer, String> {\n\n        private final String arg;\n\n        MyCollapser(String arg, boolean reqCacheEnabled) {\n            super(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                    Scope.REQUEST,\n                    new RealCollapserTimer(),\n                    HystrixCollapserProperties.Setter().withRequestCacheEnabled(reqCacheEnabled),\n                    HystrixCollapserMetrics.getInstance(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                            new HystrixPropertiesCollapserDefault(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                                    HystrixCollapserProperties.Setter())));\n            this.arg = arg;\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return arg;\n        }\n\n        @Override\n        protected HystrixCommand<List<Pair<String, Integer>>> createCommand(Collection<CollapsedRequest<Integer, String>> collapsedRequests) {\n            List<String> args = new ArrayList<String>(collapsedRequests.size());\n            for (CollapsedRequest<Integer, String> req: collapsedRequests) {\n                args.add(req.getArgument());\n            }\n            return new MyCommand(args);\n        }\n\n        @Override\n        protected void mapResponseToRequests(List<Pair<String, Integer>> batchResponse, Collection<CollapsedRequest<Integer, String>> collapsedRequests) {\n            for (Pair<String, Integer> pair: batchResponse) {\n                for (CollapsedRequest<Integer, String> collapsedReq: collapsedRequests) {\n                    if (collapsedReq.getArgument().equals(pair.a)) {\n                        collapsedReq.setResponse(pair.b);\n                    }\n                }\n            }\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return arg;\n        }\n    }\n\n\n    @Test\n    public void testDuplicateArgumentsWithRequestCachingOn() throws Exception {\n        final int NUM = 10;\n\n        List<Observable<Integer>> observables = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM; i++) {\n            MyCollapser c = new MyCollapser(\"5\", true);\n            observables.add(c.toObservable());\n        }\n\n        List<TestSubscriber<Integer>> subscribers = new ArrayList<TestSubscriber<Integer>>();\n        for (final Observable<Integer> o: observables) {\n            final TestSubscriber<Integer> sub = new TestSubscriber<Integer>();\n            subscribers.add(sub);\n\n            o.subscribe(sub);\n        }\n\n        Thread.sleep(100);\n\n        //all subscribers should receive the same value\n        for (TestSubscriber<Integer> sub: subscribers) {\n            sub.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);\n            System.out.println(\"Subscriber received : \" + sub.getOnNextEvents());\n            sub.assertNoErrors();\n            sub.assertValues(5);\n        }\n    }\n\n    @Test\n    public void testDuplicateArgumentsWithRequestCachingOff() throws Exception {\n        final int NUM = 10;\n\n        List<Observable<Integer>> observables = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM; i++) {\n            MyCollapser c = new MyCollapser(\"5\", false);\n            observables.add(c.toObservable());\n        }\n\n        List<TestSubscriber<Integer>> subscribers = new ArrayList<TestSubscriber<Integer>>();\n        for (final Observable<Integer> o: observables) {\n            final TestSubscriber<Integer> sub = new TestSubscriber<Integer>();\n            subscribers.add(sub);\n\n            o.subscribe(sub);\n        }\n\n        Thread.sleep(100);\n\n        AtomicInteger numErrors = new AtomicInteger(0);\n        AtomicInteger numValues = new AtomicInteger(0);\n\n        // only the first subscriber should receive the value.\n        // the others should get an error that the batch contains duplicates\n        for (TestSubscriber<Integer> sub: subscribers) {\n            sub.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);\n            if (sub.getOnCompletedEvents().isEmpty()) {\n                System.out.println(Thread.currentThread().getName() + \" Error : \" + sub.getOnErrorEvents());\n                sub.assertError(IllegalArgumentException.class);\n                sub.assertNoValues();\n                numErrors.getAndIncrement();\n\n            } else {\n                System.out.println(Thread.currentThread().getName() + \" OnNext : \" + sub.getOnNextEvents());\n                sub.assertValues(5);\n                sub.assertCompleted();\n                sub.assertNoErrors();\n                numValues.getAndIncrement();\n            }\n        }\n\n        assertEquals(1, numValues.get());\n        assertEquals(NUM - 1, numErrors.get());\n    }\n\n    @Test\n    public void testUnsubscribeFromSomeDuplicateArgsDoesNotRemoveFromBatch() throws Exception {\n        final int NUM = 10;\n\n        List<Observable<Integer>> observables = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM; i++) {\n            MyCollapser c = new MyCollapser(\"5\", true);\n            observables.add(c.toObservable());\n        }\n\n        List<TestSubscriber<Integer>> subscribers = new ArrayList<TestSubscriber<Integer>>();\n        List<Subscription> subscriptions = new ArrayList<Subscription>();\n\n        for (final Observable<Integer> o: observables) {\n            final TestSubscriber<Integer> sub = new TestSubscriber<Integer>();\n            subscribers.add(sub);\n\n            Subscription s = o.subscribe(sub);\n            subscriptions.add(s);\n        }\n\n\n        //unsubscribe from all but 1\n        for (int i = 0; i < NUM - 1; i++) {\n            Subscription s = subscriptions.get(i);\n            s.unsubscribe();\n        }\n\n        Thread.sleep(100);\n\n        //all subscribers with an active subscription should receive the same value\n        for (TestSubscriber<Integer> sub: subscribers) {\n            if (!sub.isUnsubscribed()) {\n                sub.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);\n                System.out.println(\"Subscriber received : \" + sub.getOnNextEvents());\n                sub.assertNoErrors();\n                sub.assertValues(5);\n            } else {\n                System.out.println(\"Subscriber is unsubscribed\");\n            }\n        }\n    }\n\n    @Test\n    public void testUnsubscribeOnOneDoesntKillBatch() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestRequestCollapser(timer, 2).queue();\n\n        // kill the first\n        response1.cancel(true);\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        // the first is cancelled so should return null\n        try {\n            response1.get(1000, TimeUnit.MILLISECONDS);\n            fail(\"expect CancellationException after cancelling\");\n        } catch (CancellationException e) {\n            // expected\n        }\n        // we should still get a response on the second\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testShardedRequests() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestShardedRequestCollapser(timer, \"1a\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestShardedRequestCollapser(timer, \"2b\").queue();\n        Future<String> response3 = new TestShardedRequestCollapser(timer, \"3b\").queue();\n        Future<String> response4 = new TestShardedRequestCollapser(timer, \"4a\").queue();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1a\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2b\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3b\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4a\", response4.get(1000, TimeUnit.MILLISECONDS));\n\n        /* we should get 2 batches since it gets sharded */\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testRequestScope() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, \"1\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestRequestCollapser(timer, \"2\").queue();\n\n        // simulate a new request\n        RequestCollapserFactory.resetRequest();\n\n        Future<String> response3 = new TestRequestCollapser(timer, \"3\").queue();\n        Future<String> response4 = new TestRequestCollapser(timer, \"4\").queue();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4\", response4.get(1000, TimeUnit.MILLISECONDS));\n\n        // 2 different batches should execute, 1 per request\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testGlobalScope() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestGloballyScopedRequestCollapser(timer, \"1\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestGloballyScopedRequestCollapser(timer, \"2\").queue();\n\n        // simulate a new request\n        RequestCollapserFactory.resetRequest();\n\n        Future<String> response3 = new TestGloballyScopedRequestCollapser(timer, \"3\").queue();\n        Future<String> response4 = new TestGloballyScopedRequestCollapser(timer, \"4\").queue();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4\", response4.get(1000, TimeUnit.MILLISECONDS));\n\n        // despite having cleared the cache in between we should have a single execution because this is on the global not request cache\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(4, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testErrorHandlingViaFutureException() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapserWithFaultyCreateCommand(timer, \"1\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestRequestCollapserWithFaultyCreateCommand(timer, \"2\").queue();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        try {\n            response1.get(1000, TimeUnit.MILLISECONDS);\n            fail(\"we should have received an exception\");\n        } catch (ExecutionException e) {\n            // what we expect\n        }\n        try {\n            response2.get(1000, TimeUnit.MILLISECONDS);\n            fail(\"we should have received an exception\");\n        } catch (ExecutionException e) {\n            // what we expect\n        }\n\n        assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    @Test\n    public void testErrorHandlingWhenMapToResponseFails() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapserWithFaultyMapToResponse(timer, \"1\");\n        Future<String> response1 = collapser1.queue();\n        Future<String> response2 = new TestRequestCollapserWithFaultyMapToResponse(timer, \"2\").queue();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        try {\n            response1.get(1000, TimeUnit.MILLISECONDS);\n            fail(\"we should have received an exception\");\n        } catch (ExecutionException e) {\n            // what we expect\n        }\n        try {\n            response2.get(1000, TimeUnit.MILLISECONDS);\n            fail(\"we should have received an exception\");\n        } catch (ExecutionException e) {\n            // what we expect\n        }\n\n        // the batch failed so no executions\n        // but it still executed the command once\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testRequestVariableLifecycle1() throws Exception {\n        HystrixRequestContext reqContext = HystrixRequestContext.initializeContext();\n\n        // do actual work\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Future<String> response1 = collapser1.queue();\n        timer.incrementTime(5);\n        Future<String> response2 = new TestRequestCollapser(timer, 2).queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response3 = new TestRequestCollapser(timer, 3).queue();\n        timer.incrementTime(6);\n        Future<String> response4 = new TestRequestCollapser(timer, 4).queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response5 = new TestRequestCollapser(timer, 5).queue();\n        timer.incrementTime(10);\n        // should execute here\n\n        // wait for all tasks to complete\n        assertEquals(\"1\", response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4\", response4.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"5\", response5.get(1000, TimeUnit.MILLISECONDS));\n\n        // each task should have been executed 3 times\n        for (TestCollapserTimer.ATask t : timer.tasks) {\n            assertEquals(3, t.task.count.get());\n        }\n\n        System.out.println(\"timer.tasks.size() A: \" + timer.tasks.size());\n        System.out.println(\"tasks in test: \" + timer.tasks);\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n\n        System.out.println(\"timer.tasks.size() B: \" + timer.tasks.size());\n\n        HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> rv = RequestCollapserFactory.getRequestVariable(new TestRequestCollapser(timer, 1).getCollapserKey().name());\n\n        reqContext.close();\n\n        assertNotNull(rv);\n        // they should have all been removed as part of ThreadContext.remove()\n        assertEquals(0, timer.tasks.size());\n    }\n\n    @Test\n    public void testRequestVariableLifecycle2() throws Exception {\n        final HystrixRequestContext reqContext = HystrixRequestContext.initializeContext();\n\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        final ConcurrentLinkedQueue<Future<String>> responses = new ConcurrentLinkedQueue<Future<String>>();\n        ConcurrentLinkedQueue<Thread> threads = new ConcurrentLinkedQueue<Thread>();\n\n        // kick off work (simulating a single request with multiple threads)\n        for (int t = 0; t < 5; t++) {\n            final int outerLoop = t;\n            Thread th = new Thread(new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n                @Override\n                public void run() {\n                    for (int i = 0; i < 100; i++) {\n                        int uniqueInt = (outerLoop * 100) + i;\n                        responses.add(new TestRequestCollapser(timer, uniqueInt).queue());\n                    }\n                }\n            }));\n\n            threads.add(th);\n            th.start();\n        }\n\n        for (Thread th : threads) {\n            // wait for each thread to finish\n            th.join();\n        }\n\n        // we expect 5 threads * 100 responses each\n        assertEquals(500, responses.size());\n\n        for (Future<String> f : responses) {\n            // they should not be done yet because the counter hasn't incremented\n            assertFalse(f.isDone());\n        }\n\n        timer.incrementTime(5);\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 2);\n        Future<String> response2 = collapser1.queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response3 = new TestRequestCollapser(timer, 3).queue();\n        timer.incrementTime(6);\n        Future<String> response4 = new TestRequestCollapser(timer, 4).queue();\n        timer.incrementTime(8);\n        // should execute here\n        Future<String> response5 = new TestRequestCollapser(timer, 5).queue();\n        timer.incrementTime(10);\n        // should execute here\n\n        // wait for all tasks to complete\n        for (Future<String> f : responses) {\n            f.get(1000, TimeUnit.MILLISECONDS);\n        }\n        assertEquals(\"2\", response2.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"3\", response3.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"4\", response4.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"5\", response5.get(1000, TimeUnit.MILLISECONDS));\n\n        // each task should have been executed 3 times\n        for (TestCollapserTimer.ATask t : timer.tasks) {\n            assertEquals(3, t.task.count.get());\n        }\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(500, cmdIterator.next().getNumberCollapsed());\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n\n        HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> rv = RequestCollapserFactory.getRequestVariable(new TestRequestCollapser(timer, 1).getCollapserKey().name());\n\n        reqContext.close();\n\n        assertNotNull(rv);\n        // they should have all been removed as part of ThreadContext.remove()\n        assertEquals(0, timer.tasks.size());\n    }\n\n    /**\n     * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future\n     */\n    @Test\n    public void testRequestCache1() {\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"A\", true);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"A\", true);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"A\", f2.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        Future<String> f3 = command1.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f3.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        // we should still have executed only one command\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[1])[0];\n        System.out.println(\"command.getExecutionEvents(): \" + command.getExecutionEvents());\n        assertEquals(2, command.getExecutionEvents().size());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test Request scoped caching doesn't prevent different ones from executing\n     */\n    @Test\n    public void testRequestCache2() {\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"A\", true);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"B\", true);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f2.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        Future<String> f3 = command1.queue();\n        Future<String> f4 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f3.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f4.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        // we should still have executed only one command\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[1])[0];\n        assertEquals(2, command.getExecutionEvents().size());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testRequestCache3() {\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"A\", true);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"B\", true);\n        SuccessfulCacheableCollapsedCommand command3 = new SuccessfulCacheableCollapsedCommand(timer, \"B\", true);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f2.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f3.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        Future<String> f4 = command1.queue();\n        Future<String> f5 = command2.queue();\n        Future<String> f6 = command3.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f4.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f5.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f6.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        // we should still have executed only one command\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[1])[0];\n        assertEquals(2, command.getExecutionEvents().size());\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testNoRequestCache3() {\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"A\", false);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"B\", false);\n        SuccessfulCacheableCollapsedCommand command3 = new SuccessfulCacheableCollapsedCommand(timer, \"B\", false);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f2.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f3.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        Future<String> f4 = command1.queue();\n        Future<String> f5 = command2.queue();\n        Future<String> f6 = command3.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f4.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f5.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"B\", f6.get(1000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        // request caching is turned off on this so we expect 2 command executions\n        assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        // we expect to see it with SUCCESS and COLLAPSED and both\n        HystrixInvokableInfo<?> commandA = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[2])[0];\n        assertEquals(2, commandA.getExecutionEvents().size());\n        assertTrue(commandA.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(commandA.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        // we expect to see it with SUCCESS and COLLAPSED and both\n        HystrixInvokableInfo<?> commandB = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[2])[1];\n        assertEquals(2, commandB.getExecutionEvents().size());\n        assertTrue(commandB.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(commandB.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());  //1 for A, 1 for B.  Batch contains only unique arguments (no duplicates)\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());  //1 for A, 1 for B.  Batch contains only unique arguments (no duplicates)\n    }\n\n    /**\n     * Test command that uses a null request argument\n     */\n    @Test\n    public void testRequestCacheWithNullRequestArgument() throws Exception {\n        ConcurrentLinkedQueue<HystrixCommand<List<String>>> commands = new ConcurrentLinkedQueue<HystrixCommand<List<String>>>();\n\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, null, true, commands);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, null, true, commands);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        assertEquals(\"NULL\", f1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(\"NULL\", f2.get(1000, TimeUnit.MILLISECONDS));\n\n        // it should have executed 1 command\n        assertEquals(1, commands.size());\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.SUCCESS));\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Future<String> f3 = command1.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        assertEquals(\"NULL\", f3.get(1000, TimeUnit.MILLISECONDS));\n\n        // it should still be 1 ... no new executions\n        assertEquals(1, commands.size());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n\n    @Test\n    public void testRequestCacheWithCommandError() {\n        ConcurrentLinkedQueue<HystrixCommand<List<String>>> commands = new ConcurrentLinkedQueue<HystrixCommand<List<String>>>();\n\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"FAILURE\", true, commands);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"FAILURE\", true, commands);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"A\", f2.get(1000, TimeUnit.MILLISECONDS));\n            fail(\"exception should have been thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        // it should have executed 1 command\n        assertEquals(1, commands.size());\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.FAILURE));\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Future<String> f3 = command1.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f3.get(1000, TimeUnit.MILLISECONDS));\n            fail(\"exception should have been thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        // it should still be 1 ... no new executions\n        assertEquals(1, commands.size());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test that a command that times out will still be cached and when retrieved will re-throw the exception.\n     */\n    @Test\n    public void testRequestCacheWithCommandTimeout() {\n        ConcurrentLinkedQueue<HystrixCommand<List<String>>> commands = new ConcurrentLinkedQueue<HystrixCommand<List<String>>>();\n\n        final TestCollapserTimer timer = new TestCollapserTimer();\n        SuccessfulCacheableCollapsedCommand command1 = new SuccessfulCacheableCollapsedCommand(timer, \"TIMEOUT\", true, commands);\n        SuccessfulCacheableCollapsedCommand command2 = new SuccessfulCacheableCollapsedCommand(timer, \"TIMEOUT\", true, commands);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f1.get(1000, TimeUnit.MILLISECONDS));\n            assertEquals(\"A\", f2.get(1000, TimeUnit.MILLISECONDS));\n            fail(\"exception should have been thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        // it should have executed 1 command\n        assertEquals(1, commands.size());\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.TIMEOUT));\n        assertTrue(commands.peek().getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n\n        Future<String> f3 = command1.queue();\n\n        // increment past batch time so it executes\n        timer.incrementTime(15);\n\n        try {\n            assertEquals(\"A\", f3.get(1000, TimeUnit.MILLISECONDS));\n            fail(\"exception should have been thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        // it should still be 1 ... no new executions\n        assertEquals(1, commands.size());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test how the collapser behaves when the circuit is short-circuited\n     */\n    @Test\n    public void testRequestWithCommandShortCircuited() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapserWithShortCircuitedCommand(timer, \"1\");\n        Observable<String> response1 = collapser1.observe();\n        Observable<String> response2 = new TestRequestCollapserWithShortCircuitedCommand(timer, \"2\").observe();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        try {\n            response1.toBlocking().first();\n            fail(\"we should have received an exception\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            // what we expect\n        }\n        try {\n            response2.toBlocking().first();\n            fail(\"we should have received an exception\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            // what we expect\n        }\n\n        // it will execute once (short-circuited)\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test a Void response type - null being set as response.\n     *\n     * @throws Exception\n     */\n    @Test\n    public void testVoidResponseTypeFireAndForgetCollapsing1() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        TestCollapserWithVoidResponseType collapser1 = new TestCollapserWithVoidResponseType(timer, 1);\n        Future<Void> response1 = collapser1.queue();\n        Future<Void> response2 = new TestCollapserWithVoidResponseType(timer, 2).queue();\n        timer.incrementTime(100); // let time pass that equals the default delay/period\n\n        // normally someone wouldn't wait on these, but we need to make sure they do in fact return\n        // and not block indefinitely in case someone does call get()\n        assertEquals(null, response1.get(1000, TimeUnit.MILLISECONDS));\n        assertEquals(null, response2.get(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test a Void response type - response never being set in mapResponseToRequest\n     *\n     * @throws Exception\n     */\n    @Test\n    public void testVoidResponseTypeFireAndForgetCollapsing2() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        TestCollapserWithVoidResponseTypeAndMissingMapResponseToRequests collapser1 = new TestCollapserWithVoidResponseTypeAndMissingMapResponseToRequests(timer, 1);\n        Future<Void> response1 = collapser1.queue();\n        new TestCollapserWithVoidResponseTypeAndMissingMapResponseToRequests(timer, 2).queue();\n        timer.incrementTime(100); // let time pass that equals the default delay/period\n\n        // we will fetch one of these just so we wait for completion ... but expect an error\n        try {\n            assertEquals(null, response1.get(1000, TimeUnit.MILLISECONDS));\n            fail(\"expected an error as mapResponseToRequests did not set responses\");\n        } catch (ExecutionException e) {\n            assertTrue(e.getCause() instanceof IllegalStateException);\n            assertTrue(e.getCause().getMessage().startsWith(\"No response set by\"));\n        }\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    /**\n     * Test a Void response type with execute - response being set in mapResponseToRequest to null\n     *\n     * @throws Exception\n     */\n    @Test\n    public void testVoidResponseTypeFireAndForgetCollapsing3() throws Exception {\n        CollapserTimer timer = new RealCollapserTimer();\n        TestCollapserWithVoidResponseType collapser1 = new TestCollapserWithVoidResponseType(timer, 1);\n        assertNull(collapser1.execute());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(1, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void testEarlyUnsubscribeExecutedViaToObservable() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.toObservable();\n        HystrixCollapser<List<String>, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.toObservable();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"2\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixCollapserMetrics metrics = collapser1.getMetrics();\n        assertSame(metrics, collapser2.getMetrics());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertEquals(1, command.getNumberCollapsed()); //1 should have been removed from batch\n    }\n\n    @Test\n    public void testEarlyUnsubscribeExecutedViaObserve() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"2\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixCollapserMetrics metrics = collapser1.getMetrics();\n        assertSame(metrics, collapser2.getMetrics());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertEquals(1, command.getNumberCollapsed()); //1 should have been removed from batch\n    }\n\n    @Test\n    public void testEarlyUnsubscribeFromAllCancelsBatch() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s2.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertNull(value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndCacheHitUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s2.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(\"foo\", value1.get());\n        assertNull(value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndOriginalUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"foo\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsOriginalAndOneCacheHitUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n        HystrixCollapser<List<String>, String, String> collapser3 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response3 = collapser3.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final CountDownLatch latch3 = new CountDownLatch(1);\n\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n        final AtomicReference<String> value3 = new AtomicReference<String>(null);\n\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        Subscription s3 = response3\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 Unsubscribed!\");\n                        latch3.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnCompleted\");\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnError : \" + e);\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnNext : \" + s);\n                        value3.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s3.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"foo\", value2.get());\n        assertNull(value3.get());\n\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsAllUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixCollapser<List<String>, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixCollapser<List<String>, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n        HystrixCollapser<List<String>, String, String> collapser3 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response3 = collapser3.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final CountDownLatch latch3 = new CountDownLatch(1);\n\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n        final AtomicReference<String> value3 = new AtomicReference<String>(null);\n\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        Subscription s3 = response3\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 Unsubscribed!\");\n                        latch3.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnCompleted\");\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnError : \" + e);\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnNext : \" + s);\n                        value3.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s2.unsubscribe();\n        s3.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertNull(value2.get());\n        assertNull(value3.get());\n\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    protected void assertCommandExecutionEvents(HystrixInvokableInfo<?> command, HystrixEventType... expectedEventTypes) {\n        boolean emitExpected = false;\n        int expectedEmitCount = 0;\n\n        boolean fallbackEmitExpected = false;\n        int expectedFallbackEmitCount = 0;\n\n        List<HystrixEventType> condensedEmitExpectedEventTypes = new ArrayList<HystrixEventType>();\n\n        for (HystrixEventType expectedEventType: expectedEventTypes) {\n            if (expectedEventType.equals(HystrixEventType.EMIT)) {\n                if (!emitExpected) {\n                    //first EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.EMIT);\n                }\n                emitExpected = true;\n                expectedEmitCount++;\n            } else if (expectedEventType.equals(HystrixEventType.FALLBACK_EMIT)) {\n                if (!fallbackEmitExpected) {\n                    //first FALLBACK_EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.FALLBACK_EMIT);\n                }\n                fallbackEmitExpected = true;\n                expectedFallbackEmitCount++;\n            } else {\n                condensedEmitExpectedEventTypes.add(expectedEventType);\n            }\n        }\n        List<HystrixEventType> actualEventTypes = command.getExecutionEvents();\n        assertEquals(expectedEmitCount, command.getNumberEmissions());\n        assertEquals(expectedFallbackEmitCount, command.getNumberFallbackEmissions());\n        assertEquals(condensedEmitExpectedEventTypes, actualEventTypes);\n    }\n\n    private static class TestRequestCollapser extends HystrixCollapser<List<String>, String, String> {\n\n        private final String value;\n        private ConcurrentLinkedQueue<HystrixCommand<List<String>>> commandsExecuted;\n\n        public TestRequestCollapser(TestCollapserTimer timer, int value) {\n            this(timer, String.valueOf(value));\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value) {\n            this(timer, value, 10000, 10);\n        }\n\n        public TestRequestCollapser(Scope scope, TestCollapserTimer timer, String value) {\n            this(scope, timer, value, 10000, 10);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, ConcurrentLinkedQueue<HystrixCommand<List<String>>> executionLog) {\n            this(timer, value, 10000, 10, executionLog);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, int value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(timer, String.valueOf(value), defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, null);\n        }\n\n        public TestRequestCollapser(Scope scope, TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(scope, timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, null);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds, ConcurrentLinkedQueue<HystrixCommand<List<String>>> executionLog) {\n            this(Scope.REQUEST, timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, executionLog);\n        }\n\n        private static HystrixCollapserMetrics createMetrics() {\n            HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"COLLAPSER_ONE\");\n            return HystrixCollapserMetrics.getInstance(key, new HystrixPropertiesCollapserDefault(key, HystrixCollapserProperties.Setter()));\n        }\n\n        public TestRequestCollapser(Scope scope, TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds, ConcurrentLinkedQueue<HystrixCommand<List<String>>> executionLog) {\n            // use a CollapserKey based on the CollapserTimer object reference so it's unique for each timer as we don't want caching\n            // of properties to occur and we're using the default HystrixProperty which typically does caching\n            super(collapserKeyFromString(timer), scope, timer, HystrixCollapserProperties.Setter().withMaxRequestsInBatch(defaultMaxRequestsInBatch).withTimerDelayInMilliseconds(defaultTimerDelayInMilliseconds), createMetrics());\n            this.value = value;\n            this.commandsExecuted = executionLog;\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return value;\n        }\n\n        @Override\n        public HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, String>> requests) {\n            /* return a mocked command */\n            HystrixCommand<List<String>> command = new TestCollapserCommand(requests);\n            if (commandsExecuted != null) {\n                commandsExecuted.add(command);\n            }\n            return command;\n        }\n\n        @Override\n        public void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, String>> requests) {\n            // for simplicity I'll assume it's a 1:1 mapping between lists ... in real implementations they often need to index to maps\n            // to allow random access as the response size does not match the request size\n            if (batchResponse.size() != requests.size()) {\n                throw new RuntimeException(\"lists don't match in size => \" + batchResponse.size() + \" : \" + requests.size());\n            }\n            int i = 0;\n            for (CollapsedRequest<String, String> request : requests) {\n                request.setResponse(batchResponse.get(i++));\n            }\n\n        }\n\n    }\n\n    /**\n     * Shard on the artificially provided 'type' variable.\n     */\n    private static class TestShardedRequestCollapser extends TestRequestCollapser {\n\n        public TestShardedRequestCollapser(TestCollapserTimer timer, String value) {\n            super(timer, value);\n        }\n\n        @Override\n        protected Collection<Collection<CollapsedRequest<String, String>>> shardRequests(Collection<CollapsedRequest<String, String>> requests) {\n            Collection<CollapsedRequest<String, String>> typeA = new ArrayList<CollapsedRequest<String, String>>();\n            Collection<CollapsedRequest<String, String>> typeB = new ArrayList<CollapsedRequest<String, String>>();\n\n            for (CollapsedRequest<String, String> request : requests) {\n                if (request.getArgument().endsWith(\"a\")) {\n                    typeA.add(request);\n                } else if (request.getArgument().endsWith(\"b\")) {\n                    typeB.add(request);\n                }\n            }\n\n            ArrayList<Collection<CollapsedRequest<String, String>>> shards = new ArrayList<Collection<CollapsedRequest<String, String>>>();\n            shards.add(typeA);\n            shards.add(typeB);\n            return shards;\n        }\n\n    }\n\n    /**\n     * Test the global scope\n     */\n    private static class TestGloballyScopedRequestCollapser extends TestRequestCollapser {\n\n        public TestGloballyScopedRequestCollapser(TestCollapserTimer timer, String value) {\n            super(Scope.GLOBAL, timer, value);\n        }\n\n    }\n\n    /**\n     * Throw an exception when creating a command.\n     */\n    private static class TestRequestCollapserWithFaultyCreateCommand extends TestRequestCollapser {\n\n        public TestRequestCollapserWithFaultyCreateCommand(TestCollapserTimer timer, String value) {\n            super(timer, value);\n        }\n\n        @Override\n        public HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> requests) {\n            throw new RuntimeException(\"some failure\");\n        }\n\n    }\n\n    /**\n     * Throw an exception when creating a command.\n     */\n    private static class TestRequestCollapserWithShortCircuitedCommand extends TestRequestCollapser {\n\n        public TestRequestCollapserWithShortCircuitedCommand(TestCollapserTimer timer, String value) {\n            super(timer, value);\n        }\n\n        @Override\n        public HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> requests) {\n            // args don't matter as it's short-circuited\n            return new ShortCircuitedCommand();\n        }\n\n    }\n\n    /**\n     * Throw an exception when mapToResponse is invoked\n     */\n    private static class TestRequestCollapserWithFaultyMapToResponse extends TestRequestCollapser {\n\n        public TestRequestCollapserWithFaultyMapToResponse(TestCollapserTimer timer, String value) {\n            super(timer, value);\n        }\n\n        @Override\n        public void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, String>> requests) {\n            // pretend we blow up with an NPE\n            throw new NullPointerException(\"batchResponse was null and we blew up\");\n        }\n\n    }\n\n    private static class TestCollapserCommand extends TestHystrixCommand<List<String>> {\n\n        private final Collection<CollapsedRequest<String, String>> requests;\n\n        TestCollapserCommand(Collection<CollapsedRequest<String, String>> requests) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(500)));\n            this.requests = requests;\n        }\n\n        @Override\n        protected List<String> run() {\n            System.out.println(\">>> TestCollapserCommand run() ... batch size: \" + requests.size());\n            // simulate a batch request\n            ArrayList<String> response = new ArrayList<String>();\n            for (CollapsedRequest<String, String> request : requests) {\n                if (request.getArgument() == null) {\n                    response.add(\"NULL\");\n                } else {\n                    if (request.getArgument().equals(\"FAILURE\")) {\n                        throw new NullPointerException(\"Simulated Error\");\n                    }\n                    if (request.getArgument().equals(\"TIMEOUT\")) {\n                        try {\n                            Thread.sleep(800);\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                    response.add(request.getArgument());\n                }\n            }\n            return response;\n        }\n\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCollapsedCommand extends TestRequestCollapser {\n\n        private final boolean cacheEnabled;\n\n        public SuccessfulCacheableCollapsedCommand(TestCollapserTimer timer, String value, boolean cacheEnabled) {\n            super(timer, value);\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        public SuccessfulCacheableCollapsedCommand(TestCollapserTimer timer, String value, boolean cacheEnabled, ConcurrentLinkedQueue<HystrixCommand<List<String>>> executionLog) {\n            super(timer, value, executionLog);\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return \"aCacheKey_\" + super.value;\n            else\n                return null;\n        }\n    }\n\n    private static class ShortCircuitedCommand extends HystrixCommand<List<String>> {\n\n        protected ShortCircuitedCommand() {\n            super(HystrixCommand.Setter.withGroupKey(\n                    HystrixCommandGroupKey.Factory.asKey(\"shortCircuitedCommand\"))\n                    .andCommandPropertiesDefaults(HystrixCommandPropertiesTest\n                            .getUnitTestPropertiesSetter()\n                            .withCircuitBreakerForceOpen(true)));\n        }\n\n        @Override\n        protected List<String> run() throws Exception {\n            System.out.println(\"*** execution (this shouldn't happen)\");\n            // this won't ever get called as we're forcing short-circuiting\n            ArrayList<String> values = new ArrayList<String>();\n            values.add(\"hello\");\n            return values;\n        }\n\n    }\n\n    private static class FireAndForgetCommand extends HystrixCommand<Void> {\n\n        protected FireAndForgetCommand(List<Integer> values) {\n            super(HystrixCommand.Setter.withGroupKey(\n                    HystrixCommandGroupKey.Factory.asKey(\"fireAndForgetCommand\"))\n                    .andCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()));\n        }\n\n        @Override\n        protected Void run() throws Exception {\n            System.out.println(\"*** FireAndForgetCommand execution: \" + Thread.currentThread());\n            return null;\n        }\n\n    }\n\n    /* package */ static class TestCollapserTimer implements CollapserTimer {\n\n        private final ConcurrentLinkedQueue<ATask> tasks = new ConcurrentLinkedQueue<ATask>();\n\n        @Override\n        public Reference<TimerListener> addListener(final TimerListener collapseTask) {\n            tasks.add(new ATask(new TestTimerListener(collapseTask)));\n\n            /**\n             * This is a hack that overrides 'clear' of a WeakReference to match the required API\n             * but then removes the strong-reference we have inside 'tasks'.\n             * <p>\n             * We do this so our unit tests know if the WeakReference is cleared correctly, and if so then the ATack is removed from 'tasks'\n             */\n            return new SoftReference<TimerListener>(collapseTask) {\n                @Override\n                public void clear() {\n                    // super.clear();\n                    for (ATask t : tasks) {\n                        if (t.task.actualListener.equals(collapseTask)) {\n                            tasks.remove(t);\n                        }\n                    }\n                }\n\n            };\n        }\n\n        /**\n         * Increment time by X. Note that incrementing by multiples of delay or period time will NOT execute multiple times.\n         * <p>\n         * You must call incrementTime multiple times each increment being larger than 'period' on subsequent calls to cause multiple executions.\n         * <p>\n         * This is because executing multiple times in a tight-loop would not achieve the correct behavior, such as batching, since it will all execute \"now\" not after intervals of time.\n         *\n         * @param timeInMilliseconds amount of time to increment\n         */\n        public synchronized void incrementTime(int timeInMilliseconds) {\n            for (ATask t : tasks) {\n                t.incrementTime(timeInMilliseconds);\n            }\n        }\n\n        private static class ATask {\n            final TestTimerListener task;\n            final int delay = 10;\n\n            // our relative time that we'll use\n            volatile int time = 0;\n            volatile int executionCount = 0;\n\n            private ATask(TestTimerListener task) {\n                this.task = task;\n            }\n\n            public synchronized void incrementTime(int timeInMilliseconds) {\n                time += timeInMilliseconds;\n                if (task != null) {\n                    if (executionCount == 0) {\n                        System.out.println(\"ExecutionCount 0 => Time: \" + time + \" Delay: \" + delay);\n                        if (time >= delay) {\n                            // first execution, we're past the delay time\n                            executeTask();\n                        }\n                    } else {\n                        System.out.println(\"ExecutionCount 1+ => Time: \" + time + \" Delay: \" + delay);\n                        if (time >= delay) {\n                            // subsequent executions, we're past the interval time\n                            executeTask();\n                        }\n                    }\n                }\n            }\n\n            private synchronized void executeTask() {\n                System.out.println(\"Executing task ...\");\n                task.tick();\n                this.time = 0; // we reset time after each execution\n                this.executionCount++;\n                System.out.println(\"executionCount: \" + executionCount);\n            }\n        }\n\n    }\n\n    private static class TestTimerListener implements TimerListener {\n\n        private final TimerListener actualListener;\n        private final AtomicInteger count = new AtomicInteger();\n\n        public TestTimerListener(TimerListener actual) {\n            this.actualListener = actual;\n        }\n\n        @Override\n        public void tick() {\n            count.incrementAndGet();\n            actualListener.tick();\n        }\n\n        @Override\n        public int getIntervalTimeInMilliseconds() {\n            return 10;\n        }\n\n    }\n\n    private static HystrixCollapserKey collapserKeyFromString(final Object o) {\n        return new HystrixCollapserKey() {\n\n            @Override\n            public String name() {\n                return String.valueOf(o);\n            }\n\n        };\n    }\n\n    private static class TestCollapserWithVoidResponseType extends HystrixCollapser<Void, Void, Integer> {\n\n        private final Integer value;\n\n        public TestCollapserWithVoidResponseType(CollapserTimer timer, int value) {\n            super(collapserKeyFromString(timer), Scope.REQUEST, timer, HystrixCollapserProperties.Setter().withMaxRequestsInBatch(1000).withTimerDelayInMilliseconds(50));\n            this.value = value;\n        }\n\n        @Override\n        public Integer getRequestArgument() {\n            return value;\n        }\n\n        @Override\n        protected HystrixCommand<Void> createCommand(Collection<CollapsedRequest<Void, Integer>> requests) {\n\n            ArrayList<Integer> args = new ArrayList<Integer>();\n            for (CollapsedRequest<Void, Integer> request : requests) {\n                args.add(request.getArgument());\n            }\n            return new FireAndForgetCommand(args);\n        }\n\n        @Override\n        protected void mapResponseToRequests(Void batchResponse, Collection<CollapsedRequest<Void, Integer>> requests) {\n            for (CollapsedRequest<Void, Integer> r : requests) {\n                r.setResponse(null);\n            }\n        }\n\n    }\n\n    private static class TestCollapserWithVoidResponseTypeAndMissingMapResponseToRequests extends HystrixCollapser<Void, Void, Integer> {\n\n        private final Integer value;\n\n        public TestCollapserWithVoidResponseTypeAndMissingMapResponseToRequests(CollapserTimer timer, int value) {\n            super(collapserKeyFromString(timer), Scope.REQUEST, timer, HystrixCollapserProperties.Setter().withMaxRequestsInBatch(1000).withTimerDelayInMilliseconds(50));\n            this.value = value;\n        }\n\n        @Override\n        public Integer getRequestArgument() {\n            return value;\n        }\n\n        @Override\n        protected HystrixCommand<Void> createCommand(Collection<CollapsedRequest<Void, Integer>> requests) {\n\n            ArrayList<Integer> args = new ArrayList<Integer>();\n            for (CollapsedRequest<Void, Integer> request : requests) {\n                args.add(request.getArgument());\n            }\n            return new FireAndForgetCommand(args);\n        }\n\n        @Override\n        protected void mapResponseToRequests(Void batchResponse, Collection<CollapsedRequest<Void, Integer>> requests) {\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandMetricsTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.observers.SafeSubscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\n\npublic class HystrixCommandMetricsTest {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @Before\n    public void init() {\n        HystrixCommandMetrics.reset();\n        Hystrix.reset();\n    }\n\n    @Test\n    public void testGetErrorPercentage() {\n        String key = \"cmd-metrics-A\";\n        try {\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key, 1);\n            HystrixCommandMetrics metrics = cmd1.metrics;\n            cmd1.execute();\n            Thread.sleep(100);\n            assertEquals(0, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);\n            cmd2.execute();\n            Thread.sleep(100);\n            assertEquals(50, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd3 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd4 = new SuccessCommand(key, 1);\n            cmd3.execute();\n            cmd4.execute();\n            Thread.sleep(100);\n            assertEquals(25, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd5 = new TimeoutCommand(key);\n            HystrixCommand<Boolean> cmd6 = new TimeoutCommand(key);\n            cmd5.execute();\n            cmd6.execute();\n            Thread.sleep(100);\n            assertEquals(50, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd7 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd8 = new SuccessCommand(key, 1);\n            HystrixCommand<Boolean> cmd9 = new SuccessCommand(key, 1);\n            cmd7.execute();\n            cmd8.execute();\n            cmd9.execute();\n\n            // latent\n            HystrixCommand<Boolean> cmd10 = new SuccessCommand(key, 60);\n            cmd10.execute();\n\n            // 6 success + 1 latent success + 1 failure + 2 timeout = 10 total\n            // latent success not considered error\n            // error percentage = 1 failure + 2 timeout / 10\n            Thread.sleep(100);\n            assertEquals(30, metrics.getHealthCounts().getErrorPercentage());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred: \" + e.getMessage());\n        }\n\n    }\n\n    @Test\n    public void testBadRequestsDoNotAffectErrorPercentage() {\n        String key = \"cmd-metrics-B\";\n        try {\n\n            HystrixCommand<Boolean> cmd1 = new SuccessCommand(key ,1);\n            HystrixCommandMetrics metrics = cmd1.metrics;\n            cmd1.execute();\n            Thread.sleep(100);\n            assertEquals(0, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd2 = new FailureCommand(key, 1);\n            cmd2.execute();\n            Thread.sleep(100);\n            assertEquals(50, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd3 = new BadRequestCommand(key, 1);\n            HystrixCommand<Boolean> cmd4 = new BadRequestCommand(key, 1);\n            try {\n                cmd3.execute();\n            } catch (HystrixBadRequestException ex) {\n                System.out.println(\"Caught expected HystrixBadRequestException from cmd3\");\n            }\n            try {\n                cmd4.execute();\n            } catch (HystrixBadRequestException ex) {\n                System.out.println(\"Caught expected HystrixBadRequestException from cmd4\");\n            }\n            Thread.sleep(100);\n            assertEquals(50, metrics.getHealthCounts().getErrorPercentage());\n\n            HystrixCommand<Boolean> cmd5 = new FailureCommand(key, 1);\n            HystrixCommand<Boolean> cmd6 = new FailureCommand(key, 1);\n            cmd5.execute();\n            cmd6.execute();\n            Thread.sleep(100);\n            assertEquals(75, metrics.getHealthCounts().getErrorPercentage());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Error occurred : \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testCurrentConcurrentExecutionCount() throws InterruptedException {\n        String key = \"cmd-metrics-C\";\n\n        HystrixCommandMetrics metrics = null;\n        List<Observable<Boolean>> cmdResults = new ArrayList<Observable<Boolean>>();\n\n        int NUM_CMDS = 8;\n        for (int i = 0; i < NUM_CMDS; i++) {\n            HystrixCommand<Boolean> cmd = new SuccessCommand(key, 900);\n            if (metrics == null) {\n                metrics = cmd.metrics;\n            }\n            Observable<Boolean> eagerObservable = cmd.observe();\n            cmdResults.add(eagerObservable);\n        }\n\n        try {\n            Thread.sleep(150);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n        System.out.println(\"ReqLog: \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(NUM_CMDS, metrics.getCurrentConcurrentExecutionCount());\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        Observable.merge(cmdResults).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(\"All commands done\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(\"Error duing command execution\");\n                e.printStackTrace();\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean aBoolean) {\n\n            }\n        });\n\n        latch.await(10000, TimeUnit.MILLISECONDS);\n        assertEquals(0, metrics.getCurrentConcurrentExecutionCount());\n    }\n\n    private class Command extends HystrixCommand<Boolean> {\n\n        private final boolean shouldFail;\n        private final boolean shouldFailWithBadRequest;\n        private final long latencyToAdd;\n\n        public Command(String commandKey, boolean shouldFail, boolean shouldFailWithBadRequest, long latencyToAdd) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"Command\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))\n                    .andCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionTimeoutInMilliseconds(1000)\n                            .withCircuitBreakerRequestVolumeThreshold(20)));\n            this.shouldFail = shouldFail;\n            this.shouldFailWithBadRequest = shouldFailWithBadRequest;\n            this.latencyToAdd = latencyToAdd;\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            Thread.sleep(latencyToAdd);\n            if (shouldFail) {\n                throw new RuntimeException(\"induced failure\");\n            }\n            if (shouldFailWithBadRequest) {\n                throw new HystrixBadRequestException(\"bad request\");\n            }\n            return true;\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n    }\n\n    private class SuccessCommand extends Command {\n\n        SuccessCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, false, false, latencyToAdd);\n        }\n    }\n\n    private class FailureCommand extends Command {\n\n        FailureCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, true, false, latencyToAdd);\n        }\n    }\n\n    private class TimeoutCommand extends Command {\n\n        TimeoutCommand(String commandKey) {\n            super(commandKey, false, false, 2000);\n        }\n    }\n\n    private class BadRequestCommand extends Command {\n        BadRequestCommand(String commandKey, long latencyToAdd) {\n            super(commandKey, false, true, latencyToAdd);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandPropertiesTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.After;\nimport org.junit.Test;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.HystrixCommandProperties.Setter;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\n\npublic class HystrixCommandPropertiesTest {\n\n    /**\n     * Utility method for creating baseline properties for unit tests.\n     */\n    /* package */static HystrixCommandProperties.Setter getUnitTestPropertiesSetter() {\n        return new HystrixCommandProperties.Setter()\n                .withExecutionTimeoutInMilliseconds(1000)// when an execution will be timed out\n                .withExecutionTimeoutEnabled(true)\n                .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) // we want thread execution by default in tests\n                .withExecutionIsolationThreadInterruptOnTimeout(true)\n                .withExecutionIsolationThreadInterruptOnFutureCancel(true)\n                .withCircuitBreakerForceOpen(false) // we don't want short-circuiting by default\n                .withCircuitBreakerErrorThresholdPercentage(40) // % of 'marks' that must be failed to trip the circuit\n                .withMetricsRollingStatisticalWindowInMilliseconds(5000)// milliseconds back that will be tracked\n                .withMetricsRollingStatisticalWindowBuckets(5) // buckets\n                .withCircuitBreakerRequestVolumeThreshold(0) // in testing we will not have a threshold unless we're specifically testing that feature\n                .withCircuitBreakerSleepWindowInMilliseconds(5000000) // milliseconds after tripping circuit before allowing retry (by default set VERY long as we want it to effectively never allow a singleTest for most unit tests)\n                .withCircuitBreakerEnabled(true)\n                .withRequestLogEnabled(true)\n                .withExecutionIsolationSemaphoreMaxConcurrentRequests(20)\n                .withFallbackIsolationSemaphoreMaxConcurrentRequests(10)\n                .withFallbackEnabled(true)\n                .withCircuitBreakerForceClosed(false)\n                .withMetricsRollingPercentileEnabled(true)\n                .withRequestCacheEnabled(true)\n                .withMetricsRollingPercentileWindowInMilliseconds(60000)\n                .withMetricsRollingPercentileWindowBuckets(12)\n                .withMetricsRollingPercentileBucketSize(1000)\n                .withMetricsHealthSnapshotIntervalInMilliseconds(100);\n    }\n\n    /**\n     * Return a static representation of the properties with values from the Builder so that UnitTests can create properties that are not affected by the actual implementations which pick up their\n     * values dynamically.\n     * \n     * @param builder command properties builder\n     * @return HystrixCommandProperties\n     */\n    /* package */static HystrixCommandProperties asMock(final Setter builder) {\n        return new HystrixCommandProperties(TestKey.TEST) {\n\n            @Override\n            public HystrixProperty<Boolean> circuitBreakerEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerEnabled());\n            }\n\n            @Override\n            public HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerErrorThresholdPercentage());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> circuitBreakerForceClosed() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerForceClosed());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> circuitBreakerForceOpen() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerForceOpen());\n            }\n\n            @Override\n            public HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerRequestVolumeThreshold());\n            }\n\n            @Override\n            public HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds() {\n                return HystrixProperty.Factory.asProperty(builder.getCircuitBreakerSleepWindowInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionIsolationSemaphoreMaxConcurrentRequests());\n            }\n\n            @Override\n            public HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionIsolationStrategy());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionIsolationThreadInterruptOnTimeout());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> executionIsolationThreadInterruptOnFutureCancel() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionIsolationThreadInterruptOnFutureCancel());\n            }\n\n            @Override\n            public HystrixProperty<String> executionIsolationThreadPoolKeyOverride() {\n                return HystrixProperty.Factory.nullProperty();\n            }\n\n            @Override\n            public HystrixProperty<Integer> executionTimeoutInMilliseconds() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionTimeoutInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> executionTimeoutEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getExecutionTimeoutEnabled());\n            }\n\n            @Override\n            public HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests() {\n                return HystrixProperty.Factory.asProperty(builder.getFallbackIsolationSemaphoreMaxConcurrentRequests());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> fallbackEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getFallbackEnabled());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsHealthSnapshotIntervalInMilliseconds() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsHealthSnapshotIntervalInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingPercentileBucketSize() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingPercentileBucketSize());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> metricsRollingPercentileEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingPercentileEnabled());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingPercentileWindow() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingPercentileWindowInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingPercentileWindowBuckets() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingPercentileWindowBuckets());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowBuckets());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> requestCacheEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getRequestCacheEnabled());\n            }\n\n            @Override\n            public HystrixProperty<Boolean> requestLogEnabled() {\n                return HystrixProperty.Factory.asProperty(builder.getRequestLogEnabled());\n            }\n\n        };\n    }\n\n    // NOTE: We use \"unitTestPrefix\" as a prefix so we can't end up pulling in external properties that change unit test behavior\n\n    public enum TestKey implements HystrixCommandKey {\n        TEST\n    }\n\n    private static class TestPropertiesCommand extends HystrixCommandProperties {\n\n        protected TestPropertiesCommand(HystrixCommandKey key, Setter builder, String propertyPrefix) {\n            super(key, builder, propertyPrefix);\n        }\n\n    }\n\n    @After\n    public void cleanup() {\n        ConfigurationManager.getConfigInstance().clear();\n    }\n\n    @Test\n    public void testBooleanBuilderOverride1() {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(true), \"unitTestPrefix\");\n\n        // the builder override should take precedence over the default\n        assertEquals(true, properties.circuitBreakerForceClosed().get());\n    }\n\n    @Test\n    public void testBooleanBuilderOverride2() {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(false), \"unitTestPrefix\");\n\n        // the builder override should take precedence over the default\n        assertEquals(false, properties.circuitBreakerForceClosed().get());\n    }\n\n    @Test\n    public void testBooleanCodeDefault() {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), \"unitTestPrefix\");\n        assertEquals(HystrixCommandProperties.default_circuitBreakerForceClosed, properties.circuitBreakerForceClosed().get());\n    }\n\n    @Test\n    public void testBooleanGlobalDynamicOverrideOfCodeDefault() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\", true);\n\n        // the global dynamic property should take precedence over the default\n        assertEquals(true, properties.circuitBreakerForceClosed().get());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\");\n    }\n\n    @Test\n    public void testBooleanInstanceBuilderOverrideOfGlobalDynamicOverride1() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(true), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\", false);\n\n        // the builder injected should take precedence over the global dynamic property\n        assertEquals(true, properties.circuitBreakerForceClosed().get());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\");\n    }\n\n    @Test\n    public void testBooleanInstanceBuilderOverrideOfGlobalDynamicOverride2() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(false), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\", true);\n\n        // the builder injected should take precedence over the global dynamic property\n        assertEquals(false, properties.circuitBreakerForceClosed().get());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\");\n    }\n\n    @Test\n    public void testBooleanInstanceDynamicOverrideOfEverything() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceClosed(false), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\", false);\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.TEST.circuitBreaker.forceClosed\", true);\n\n        // the instance specific dynamic property should take precedence over everything\n        assertEquals(true, properties.circuitBreakerForceClosed().get());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.circuitBreaker.forceClosed\");\n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.TEST.circuitBreaker.forceClosed\");\n    }\n\n    @Test\n    public void testIntegerBuilderOverride() {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withMetricsRollingStatisticalWindowInMilliseconds(5000), \"unitTestPrefix\");\n\n        // the builder override should take precedence over the default\n        assertEquals(5000, properties.metricsRollingStatisticalWindowInMilliseconds().get().intValue());\n    }\n\n    @Test\n    public void testIntegerCodeDefault() {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), \"unitTestPrefix\");\n        assertEquals(HystrixCommandProperties.default_metricsRollingStatisticalWindow, properties.metricsRollingStatisticalWindowInMilliseconds().get());\n    }\n\n    @Test\n    public void testIntegerGlobalDynamicOverrideOfCodeDefault() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.metrics.rollingStats.timeInMilliseconds\", 1234);\n\n        // the global dynamic property should take precedence over the default\n        assertEquals(1234, properties.metricsRollingStatisticalWindowInMilliseconds().get().intValue());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.metrics.rollingStats.timeInMilliseconds\");\n    }\n\n    @Test\n    public void testIntegerInstanceBuilderOverrideOfGlobalDynamicOverride() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withMetricsRollingStatisticalWindowInMilliseconds(5000), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.rollingStats.timeInMilliseconds\", 3456);\n\n        // the builder injected should take precedence over the global dynamic property\n        assertEquals(5000, properties.metricsRollingStatisticalWindowInMilliseconds().get().intValue());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.rollingStats.timeInMilliseconds\");\n    }\n\n    @Test\n    public void testIntegerInstanceDynamicOverrideOfEverything() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST,\n                new HystrixCommandProperties.Setter().withMetricsRollingStatisticalWindowInMilliseconds(5000), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.metrics.rollingStats.timeInMilliseconds\", 1234);\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.TEST.metrics.rollingStats.timeInMilliseconds\", 3456);\n\n        // the instance specific dynamic property should take precedence over everything\n        assertEquals(3456, properties.metricsRollingStatisticalWindowInMilliseconds().get().intValue());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.metrics.rollingStats.timeInMilliseconds\");\n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.TEST.metrics.rollingStats.timeInMilliseconds\");\n    }\n\n    @Test\n    public void testThreadPoolOnlyHasInstanceOverride() throws Exception {\n        HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), \"unitTestPrefix\");\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.default.threadPoolKeyOverride\", 1234);\n        // it should be null\n        assertEquals(null, properties.executionIsolationThreadPoolKeyOverride().get());\n        ConfigurationManager.getConfigInstance().setProperty(\"unitTestPrefix.command.TEST.threadPoolKeyOverride\", \"testPool\");\n        // now it should have a value\n        assertEquals(\"testPool\", properties.executionIsolationThreadPoolKeyOverride().get());\n\n        // cleanup \n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.default.threadPoolKeyOverride\");\n        ConfigurationManager.getConfigInstance().clearProperty(\"unitTestPrefix.command.TEST.threadPoolKeyOverride\");\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.AbstractCommand.TryableSemaphore;\nimport com.netflix.hystrix.AbstractCommand.TryableSemaphoreActual;\nimport com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport org.junit.After;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Observer;\nimport rx.Scheduler;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.observers.TestSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixCommandTest extends CommonHystrixCommandTests<TestHystrixCommand<Integer>> {\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @After\n    public void cleanup() {\n        // force properties to be clean as well\n        ConfigurationManager.getConfigInstance().clear();\n\n        HystrixCommandKey key = Hystrix.getCurrentThreadExecutingCommand();\n        if (key != null) {\n            System.out.println(\"WARNING: Hystrix.getCurrentThreadExecutingCommand() should be null but got: \" + key + \". Can occur when calling queue() and never retrieving.\");\n        }\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testExecutionSuccess() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.EXECUTE_VALUE, command.execute());\n\n        assertEquals(null, command.getFailedExecutionException());\n        assertNull(command.getExecutionException());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test that a command can not be executed multiple times.\n     */\n    @Test\n    public void testExecutionMultipleTimes() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n        assertFalse(command.isExecutionComplete());\n        // first should succeed\n        assertEquals(FlexibleTestHystrixCommand.EXECUTE_VALUE, command.execute());\n        assertTrue(command.isExecutionComplete());\n        assertTrue(command.isExecutedInThread());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n        assertNull(command.getExecutionException());\n\n        try {\n            // second should fail\n            command.execute();\n            fail(\"we should not allow this ... it breaks the state of request logs\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            // we want to get here\n        }\n\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n    }\n\n    /**\n     * Test a command execution that throws an HystrixException and didn't implement getFallback.\n     */\n    @Test\n    public void testExecutionHystrixFailureWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.HYSTRIX_FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertNotNull(e.getFallbackException());\n            assertNotNull(e.getImplementingClass());\n        }\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution that throws an unknown exception (not HystrixException) and didn't implement getFallback.\n     */\n    @Test\n    public void testExecutionFailureWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertNotNull(e.getFallbackException());\n            assertNotNull(e.getImplementingClass());\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n    \n    /**\n     * Test a command execution that throws an exception that should not be wrapped.\n     */\n    @Test\n    public void testNotWrappedExceptionWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.NOT_WRAPPED_FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            fail(\"we shouldn't get a HystrixRuntimeException\");\n        } catch (RuntimeException e) {\n            assertTrue(e instanceof NotWrappedByHystrixTestRuntimeException);\n        }\n        \n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertTrue(command.getExecutionException() instanceof NotWrappedByHystrixTestRuntimeException);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution that throws an exception that should not be wrapped.\n     */\n    @Test\n    public void testNotWrappedBadRequestWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST_NOT_WRAPPED, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            fail(\"we shouldn't get a HystrixRuntimeException\");\n        } catch (RuntimeException e) {\n            assertTrue(e instanceof NotWrappedByHystrixTestRuntimeException);\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.getEventCounts().contains(HystrixEventType.BAD_REQUEST));\n        assertCommandExecutionEvents(command, HystrixEventType.BAD_REQUEST);\n        assertNotNull(command.getExecutionException());\n        assertTrue(command.getExecutionException() instanceof HystrixBadRequestException);\n        assertTrue(command.getExecutionException().getCause() instanceof NotWrappedByHystrixTestRuntimeException);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testNotWrappedBadRequestWithFallback() throws Exception {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST_NOT_WRAPPED, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            fail(\"we shouldn't get a HystrixRuntimeException\");\n        } catch (RuntimeException e) {\n            assertTrue(e instanceof NotWrappedByHystrixTestRuntimeException);\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.getEventCounts().contains(HystrixEventType.BAD_REQUEST));\n        assertCommandExecutionEvents(command, HystrixEventType.BAD_REQUEST);\n        assertNotNull(command.getExecutionException());\n        assertTrue(command.getExecutionException() instanceof HystrixBadRequestException);\n        assertTrue(command.getExecutionException().getCause() instanceof NotWrappedByHystrixTestRuntimeException);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution that fails but has a fallback.\n     */\n    @Test\n    public void testExecutionFailureWithFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.execute());\n        assertEquals(\"Execution Failure for TestHystrixCommand\", command.getFailedExecutionException().getMessage());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution that throws exception that should not be wrapped but has a fallback.\n     */\n    @Test\n    public void testNotWrappedExceptionWithFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.NOT_WRAPPED_FAILURE, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.execute());\n        assertEquals(\"Raw exception for TestHystrixCommand\", command.getFailedExecutionException().getMessage());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution that fails, has getFallback implemented but that fails as well.\n     */\n    @Test\n    public void testExecutionFailureWithFallbackFailure() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.FAILURE);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            System.out.println(\"------------------------------------------------\");\n            e.printStackTrace();\n            System.out.println(\"------------------------------------------------\");\n            assertNotNull(e.getFallbackException());\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_FAILURE);\n        assertNotNull(command.getExecutionException());\n\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a successful command execution (asynchronously).\n     */\n    @Test\n    public void testQueueSuccess() throws Exception {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n        Future<Integer> future = command.queue();\n        assertEquals(FlexibleTestHystrixCommand.EXECUTE_VALUE, future.get());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n        assertNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution (asynchronously) that throws an HystrixException and didn't implement getFallback.\n     */\n    @Test\n    public void testQueueKnownFailureWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.HYSTRIX_FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.queue().get();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e.getCause() instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e.getCause();\n\n                assertNotNull(de.getFallbackException());\n                assertNotNull(de.getImplementingClass());\n            } else {\n                fail(\"the cause should be HystrixRuntimeException\");\n            }\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution (asynchronously) that throws an unknown exception (not HystrixException) and didn't implement getFallback.\n     */\n    @Test\n    public void testQueueUnknownFailureWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.queue().get();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e.getCause() instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e.getCause();\n                assertNotNull(de.getFallbackException());\n                assertNotNull(de.getImplementingClass());\n            } else {\n                fail(\"the cause should be HystrixRuntimeException\");\n            }\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution (asynchronously) that fails but has a fallback.\n     */\n    @Test\n    public void testQueueFailureWithFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        try {\n            Future<Integer> future = command.queue();\n            assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, future.get());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution (asynchronously) that fails, has getFallback implemented but that fails as well.\n     */\n    @Test\n    public void testQueueFailureWithFallbackFailure() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.FAILURE);\n        try {\n            command.queue().get();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e.getCause() instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e.getCause();\n                e.printStackTrace();\n                assertNotNull(de.getFallbackException());\n            } else {\n                fail(\"the cause should be HystrixRuntimeException\");\n            }\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_FAILURE);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testObserveSuccess() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.EXECUTE_VALUE, command.observe().toBlocking().single());\n        assertEquals(null, command.getFailedExecutionException());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n        assertNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testCallbackThreadForThreadIsolation() throws Exception {\n\n        final AtomicReference<Thread> commandThread = new AtomicReference<Thread>();\n        final AtomicReference<Thread> subscribeThread = new AtomicReference<Thread>();\n\n        TestHystrixCommand<Boolean> command = new TestHystrixCommand<Boolean>(TestHystrixCommand.testPropsBuilder()) {\n\n            @Override\n            protected Boolean run() {\n                commandThread.set(Thread.currentThread());\n                return true;\n            }\n        };\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        command.toObservable().subscribe(new Observer<Boolean>() {\n\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                latch.countDown();\n                e.printStackTrace();\n            }\n\n            @Override\n            public void onNext(Boolean args) {\n                subscribeThread.set(Thread.currentThread());\n            }\n        });\n\n        if (!latch.await(2000, TimeUnit.MILLISECONDS)) {\n            fail(\"timed out\");\n        }\n\n        assertNotNull(commandThread.get());\n        assertNotNull(subscribeThread.get());\n\n        System.out.println(\"Command Thread: \" + commandThread.get());\n        System.out.println(\"Subscribe Thread: \" + subscribeThread.get());\n\n        assertTrue(commandThread.get().getName().startsWith(\"hystrix-\"));\n        assertTrue(subscribeThread.get().getName().startsWith(\"hystrix-\"));\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testCallbackThreadForSemaphoreIsolation() throws Exception {\n\n        final AtomicReference<Thread> commandThread = new AtomicReference<Thread>();\n        final AtomicReference<Thread> subscribeThread = new AtomicReference<Thread>();\n\n        TestHystrixCommand<Boolean> command = new TestHystrixCommand<Boolean>(TestHystrixCommand.testPropsBuilder()\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Boolean run() {\n                commandThread.set(Thread.currentThread());\n                return true;\n            }\n        };\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        command.toObservable().subscribe(new Observer<Boolean>() {\n\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                latch.countDown();\n                e.printStackTrace();\n            }\n\n            @Override\n            public void onNext(Boolean args) {\n                subscribeThread.set(Thread.currentThread());\n            }\n        });\n\n        if (!latch.await(2000, TimeUnit.MILLISECONDS)) {\n            fail(\"timed out\");\n        }\n\n        assertNotNull(commandThread.get());\n        assertNotNull(subscribeThread.get());\n\n        System.out.println(\"Command Thread: \" + commandThread.get());\n        System.out.println(\"Subscribe Thread: \" + subscribeThread.get());\n\n        String mainThreadName = Thread.currentThread().getName();\n\n        // semaphore should be on the calling thread\n        assertTrue(commandThread.get().getName().equals(mainThreadName));\n        assertTrue(subscribeThread.get().getName().equals(mainThreadName));\n    }\n\n    /**\n     * Tests that the circuit-breaker reports itself as \"OPEN\" if set as forced-open\n     */\n    @Test\n    public void testCircuitBreakerReportsOpenIfForcedOpen() {\n        HystrixCommand<Boolean> cmd = new HystrixCommand<Boolean>(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GROUP\")).andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withCircuitBreakerForceOpen(true))) {\n\n            @Override\n            protected Boolean run() throws Exception {\n                return true;\n            }\n\n            @Override\n            protected Boolean getFallback() {\n                return false;\n            }\n        };\n\n        assertFalse(cmd.execute()); //fallback should fire\n        System.out.println(\"RESULT : \" + cmd.getExecutionEvents());\n        assertTrue(cmd.isCircuitBreakerOpen());\n    }\n\n    /**\n     * Tests that the circuit-breaker reports itself as \"CLOSED\" if set as forced-closed\n     */\n    @Test\n    public void testCircuitBreakerReportsClosedIfForcedClosed() {\n        HystrixCommand<Boolean> cmd = new HystrixCommand<Boolean>(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GROUP\")).andCommandPropertiesDefaults(\n                new HystrixCommandProperties.Setter().withCircuitBreakerForceOpen(false).withCircuitBreakerForceClosed(true))) {\n\n            @Override\n            protected Boolean run() throws Exception {\n                return true;\n            }\n\n            @Override\n            protected Boolean getFallback() {\n                return false;\n            }\n        };\n\n        assertTrue(cmd.execute());\n        System.out.println(\"RESULT : \" + cmd.getExecutionEvents());\n        assertFalse(cmd.isCircuitBreakerOpen());\n    }\n\n    /**\n     * Test that the circuit-breaker is shared across HystrixCommand objects with the same CommandKey.\n     * <p>\n     * This will test HystrixCommand objects with a single circuit-breaker (as if each injected with same CommandKey)\n     * <p>\n     * Multiple HystrixCommand objects with the same dependency use the same circuit-breaker.\n     */\n    @Test\n    public void testCircuitBreakerAcrossMultipleCommandsButSameCircuitBreaker() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"SharedCircuitBreaker\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(key);\n        /* fail 3 times and then it should trip the circuit and stop executing */\n        // failure 1\n        TestHystrixCommand<Integer> attempt1 = getSharedCircuitBreakerCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker);\n        System.out.println(\"COMMAND KEY (from cmd): \" + attempt1.commandKey.name());\n        attempt1.execute();\n        Thread.sleep(100);\n        assertTrue(attempt1.isResponseFromFallback());\n        assertFalse(attempt1.isCircuitBreakerOpen());\n        assertFalse(attempt1.isResponseShortCircuited());\n\n        // failure 2 with a different command, same circuit breaker\n        TestHystrixCommand<Integer> attempt2 = getSharedCircuitBreakerCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker);\n        attempt2.execute();\n        Thread.sleep(100);\n        assertTrue(attempt2.isFailedExecution());\n        assertTrue(attempt2.isResponseFromFallback());\n        assertFalse(attempt2.isCircuitBreakerOpen());\n        assertFalse(attempt2.isResponseShortCircuited());\n\n        // failure 3 of the Hystrix, 2nd for this particular HystrixCommand\n        TestHystrixCommand<Integer> attempt3 = getSharedCircuitBreakerCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker);\n        attempt3.execute();\n        Thread.sleep(100);\n        assertTrue(attempt3.isFailedExecution());\n        assertTrue(attempt3.isResponseFromFallback());\n        assertFalse(attempt3.isResponseShortCircuited());\n\n        // it should now be 'open' and prevent further executions\n        // after having 3 failures on the Hystrix that these 2 different HystrixCommand objects are for\n        assertTrue(attempt3.isCircuitBreakerOpen());\n\n        // attempt 4\n        TestHystrixCommand<Integer> attempt4 = getSharedCircuitBreakerCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker);\n        attempt4.execute();\n        Thread.sleep(100);\n        assertTrue(attempt4.isResponseFromFallback());\n        // this should now be true as the response will be short-circuited\n        assertTrue(attempt4.isResponseShortCircuited());\n        // this should remain open\n        assertTrue(attempt4.isCircuitBreakerOpen());\n\n        assertSaneHystrixRequestLog(4);\n        assertCommandExecutionEvents(attempt1, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt2, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt3, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt4, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_SUCCESS);\n    }\n\n    /**\n     * Test that the circuit-breaker being disabled doesn't wreak havoc.\n     */\n    @Test\n    public void testExecutionSuccessWithCircuitBreakerDisabled() {\n        TestHystrixCommand<Integer> command = getCircuitBreakerDisabledCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.EXECUTE_VALUE, command.execute());\n\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        // we'll still get metrics ... just not the circuit breaker opening/closing\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n    }\n\n    /**\n     * Test a command execution timeout where the command didn't implement getFallback.\n     */\n    @Test\n    public void testExecutionTimeoutWithNoFallback() {\n        TestHystrixCommand<Integer> command = getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 50);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            //                e.printStackTrace();\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n\n        assertTrue(command.isResponseTimedOut());\n        assertFalse(command.isResponseFromFallback());\n        assertFalse(command.isResponseRejected());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution timeout where the command implemented getFallback.\n     */\n    @Test\n    public void testExecutionTimeoutWithFallback() {\n        TestHystrixCommand<Integer> command = getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.execute());\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n        assertFalse(command.isCircuitBreakerOpen());\n        assertFalse(command.isResponseShortCircuited());\n        assertTrue(command.isResponseTimedOut());\n        assertTrue(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a command execution timeout where the command implemented getFallback but it fails.\n     */\n    @Test\n    public void testExecutionTimeoutFallbackFailure() {\n        TestHystrixCommand<Integer> command = getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.FAILURE, 50);\n        try {\n            command.execute();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n\n        assertNotNull(command.getExecutionException());\n\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_FAILURE);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test that the command finishing AFTER a timeout (because thread continues in background) does not register a SUCCESS\n     */\n    @Test\n    public void testCountersOnExecutionTimeout() throws Exception {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n        command.execute();\n\n        /* wait long enough for the command to have finished */\n        Thread.sleep(200);\n\n        /* response should still be the same as 'testCircuitBreakerOnExecutionTimeout' */\n        assertTrue(command.isResponseFromFallback());\n        assertFalse(command.isCircuitBreakerOpen());\n        assertFalse(command.isResponseShortCircuited());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertFalse(command.isSuccessfulExecution());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command didn't implement getFallback.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testQueuedExecutionTimeoutWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 50);\n        try {\n            command.queue().get();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e instanceof ExecutionException && e.getCause() instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e.getCause();\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n            }\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command implemented getFallback.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testQueuedExecutionTimeoutWithFallback() throws Exception {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.queue().get());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command implemented getFallback but it fails.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testQueuedExecutionTimeoutFallbackFailure() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.FAILURE, 50);\n        try {\n            command.queue().get();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e instanceof ExecutionException && e.getCause() instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e.getCause();\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n            }\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_FAILURE);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command didn't implement getFallback.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testObservedExecutionTimeoutWithNoFallback() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 50);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n            }\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command implemented getFallback.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testObservedExecutionTimeoutWithFallback() throws Exception {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.observe().toBlocking().single());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a queued command execution timeout where the command implemented getFallback but it fails.\n     * <p>\n     * We specifically want to protect against developers queuing commands and using queue().get() without a timeout (such as queue().get(3000, TimeUnit.Milliseconds)) and ending up blocking\n     * indefinitely by skipping the timeout protection of the execute() command.\n     */\n    @Test\n    public void testObservedExecutionTimeoutFallbackFailure() {\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.FAILURE, 50);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n            }\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_FAILURE);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testShortCircuitFallbackCounter() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true);\n        KnownFailureTestCommandWithFallback command1 = new KnownFailureTestCommandWithFallback(circuitBreaker);\n        command1.execute();\n\n        KnownFailureTestCommandWithFallback command2 = new KnownFailureTestCommandWithFallback(circuitBreaker);\n        command2.execute();\n\n        // will be -1 because it never attempted execution\n        assertTrue(command1.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command1.isResponseShortCircuited());\n        assertFalse(command1.isResponseTimedOut());\n        assertNotNull(command1.getExecutionException());\n\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test when a command fails to get queued up in the threadpool where the command didn't implement getFallback.\n     * <p>\n     * We specifically want to protect against developers getting random thread exceptions and instead just correctly receiving HystrixRuntimeException when no fallback exists.\n     */\n    @Test\n    public void testRejectedThreadWithNoFallback() throws Exception {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Rejection-NoFallback\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SingleThreadedPoolWithQueue pool = new SingleThreadedPoolWithQueue(1);\n        // fill up the queue\n        pool.queue.add(new Runnable() {\n\n            @Override\n            public void run() {\n                System.out.println(\"**** queue filler1 ****\");\n                try {\n                    Thread.sleep(500);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n\n        });\n\n        Future<Boolean> f = null;\n        TestCommandRejection command1 = null;\n        TestCommandRejection command2 = null;\n        try {\n            command1 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_NOT_IMPLEMENTED);\n            f = command1.queue();\n            command2 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_NOT_IMPLEMENTED);\n            command2.queue();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"command.getExecutionTimeInMilliseconds(): \" + command2.getExecutionTimeInMilliseconds());\n            // will be -1 because it never attempted execution\n            assertTrue(command2.isResponseRejected());\n            assertFalse(command2.isResponseShortCircuited());\n            assertFalse(command2.isResponseTimedOut());\n            assertNotNull(command2.getExecutionException());\n\n            if (e instanceof HystrixRuntimeException && e.getCause() instanceof RejectedExecutionException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof RejectedExecutionException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException with cause as RejectedExecutionException\");\n            }\n        }\n\n        f.get();\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test when a command fails to get queued up in the threadpool where the command implemented getFallback.\n     * <p>\n     * We specifically want to protect against developers getting random thread exceptions and instead just correctly receives a fallback.\n     */\n    @Test\n    public void testRejectedThreadWithFallback() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Rejection-Fallback\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SingleThreadedPoolWithQueue pool = new SingleThreadedPoolWithQueue(1);\n\n        //command 1 will execute in threadpool (passing through the queue)\n        //command 2 will execute after spending time in the queue (after command1 completes)\n        //command 3 will get rejected, since it finds pool and queue both full\n        TestCommandRejection command1 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS);\n        TestCommandRejection command2 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS);\n        TestCommandRejection command3 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS);\n\n        Observable<Boolean> result1 = command1.observe();\n        Observable<Boolean> result2 = command2.observe();\n\n        Thread.sleep(100);\n        //command3 should find queue filled, and get rejected\n        assertFalse(command3.execute());\n        assertTrue(command3.isResponseRejected());\n        assertFalse(command1.isResponseRejected());\n        assertFalse(command2.isResponseRejected());\n        assertTrue(command3.isResponseFromFallback());\n        assertNotNull(command3.getExecutionException());\n\n        assertCommandExecutionEvents(command3, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_SUCCESS);\n        Observable.merge(result1, result2).toList().toBlocking().single(); //await the 2 latent commands\n\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test when a command fails to get queued up in the threadpool where the command implemented getFallback but it fails.\n     * <p>\n     * We specifically want to protect against developers getting random thread exceptions and instead just correctly receives an HystrixRuntimeException.\n     */\n    @Test\n    public void testRejectedThreadWithFallbackFailure() throws ExecutionException, InterruptedException {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SingleThreadedPoolWithQueue pool = new SingleThreadedPoolWithQueue(1);\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Rejection-A\");\n\n        TestCommandRejection command1 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_FAILURE); //this should pass through the queue and sit in the pool\n        TestCommandRejection command2 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS); //this should sit in the queue\n        TestCommandRejection command3 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_FAILURE); //this should observe full queue and get rejected\n        Future<Boolean> f1 = null;\n        Future<Boolean> f2 = null;\n        try {\n            f1 = command1.queue();\n            f2 = command2.queue();\n            assertEquals(false, command3.queue().get()); //should get thread-pool rejected\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e instanceof HystrixRuntimeException && e.getCause() instanceof RejectedExecutionException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof RejectedExecutionException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException with cause as RejectedExecutionException\");\n            }\n        }\n\n        assertCommandExecutionEvents(command1); //still in-flight, no events yet\n        assertCommandExecutionEvents(command2); //still in-flight, no events yet\n        assertCommandExecutionEvents(command3, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_FAILURE);\n        int numInFlight = circuitBreaker.metrics.getCurrentConcurrentExecutionCount();\n        assertTrue(\"Expected at most 1 in flight but got : \" + numInFlight, numInFlight <= 1); //pool-filler still going\n        //This is a case where we knowingly walk away from executing Hystrix threads. They should have an in-flight status (\"Executed\").  You should avoid this in a production environment\n        HystrixRequestLog requestLog = HystrixRequestLog.getCurrentRequest();\n        assertEquals(3, requestLog.getAllExecutedCommands().size());\n        assertTrue(requestLog.getExecutedCommandsAsString().contains(\"Executed\"));\n\n        //block on the outstanding work, so we don't inadvertently affect any other tests\n        long startTime = System.currentTimeMillis();\n        f1.get();\n        f2.get();\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        System.out.println(\"Time blocked : \" + (System.currentTimeMillis() - startTime));\n    }\n\n    /**\n     * Test that we can reject a thread using isQueueSpaceAvailable() instead of just when the pool rejects.\n     * <p>\n     * For example, we have queue size set to 100 but want to reject when we hit 10.\n     * <p>\n     * This allows us to use FastProperties to control our rejection point whereas we can't resize a queue after it's created.\n     */\n    @Test\n    public void testRejectedThreadUsingQueueSize() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Rejection-B\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SingleThreadedPoolWithQueue pool = new SingleThreadedPoolWithQueue(10, 1);\n        // put 1 item in the queue\n        // the thread pool won't pick it up because we're bypassing the pool and adding to the queue directly so this will keep the queue full\n\n        pool.queue.add(new Runnable() {\n\n            @Override\n            public void run() {\n                System.out.println(\"**** queue filler1 ****\");\n                try {\n                    Thread.sleep(500);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n\n        });\n\n\n        TestCommandRejection command = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_NOT_IMPLEMENTED);\n        try {\n            // this should fail as we already have 1 in the queue\n            command.queue();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            assertTrue(command.isResponseRejected());\n            assertFalse(command.isResponseShortCircuited());\n            assertFalse(command.isResponseTimedOut());\n            assertNotNull(command.getExecutionException());\n\n            if (e instanceof HystrixRuntimeException && e.getCause() instanceof RejectedExecutionException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof RejectedExecutionException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException with cause as RejectedExecutionException\");\n            }\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testDisabledTimeoutWorks() {\n        CommandWithDisabledTimeout cmd = new CommandWithDisabledTimeout(100, 900);\n        boolean result = cmd.execute();\n\n        assertEquals(true, result);\n        assertFalse(cmd.isResponseTimedOut());\n        assertNull(cmd.getExecutionException());\n        System.out.println(\"CMD : \" + cmd.currentRequestLog.getExecutedCommandsAsString());\n        assertTrue(cmd.executionResult.getExecutionLatency() >= 900);\n        assertCommandExecutionEvents(cmd, HystrixEventType.SUCCESS);\n    }\n\n    @Test\n    public void testFallbackSemaphore() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        // single thread should work\n        TestSemaphoreCommandWithSlowFallback command1 = new TestSemaphoreCommandWithSlowFallback(circuitBreaker, 1, 200);\n        boolean result = command1.queue().get();\n        assertTrue(result);\n\n        // 2 threads, the second should be rejected by the fallback semaphore\n        boolean exceptionReceived = false;\n        Future<Boolean> result2 = null;\n        TestSemaphoreCommandWithSlowFallback command2 = null;\n        TestSemaphoreCommandWithSlowFallback command3 = null;\n        try {\n            System.out.println(\"c2 start: \" + System.currentTimeMillis());\n            command2 = new TestSemaphoreCommandWithSlowFallback(circuitBreaker, 1, 800);\n            result2 = command2.queue();\n            System.out.println(\"c2 after queue: \" + System.currentTimeMillis());\n            // make sure that thread gets a chance to run before queuing the next one\n            Thread.sleep(50);\n            System.out.println(\"c3 start: \" + System.currentTimeMillis());\n            command3 = new TestSemaphoreCommandWithSlowFallback(circuitBreaker, 1, 200);\n            Future<Boolean> result3 = command3.queue();\n            System.out.println(\"c3 after queue: \" + System.currentTimeMillis());\n            result3.get();\n        } catch (Exception e) {\n            e.printStackTrace();\n            exceptionReceived = true;\n        }\n\n        assertTrue(result2.get());\n\n        if (!exceptionReceived) {\n            fail(\"We expected an exception on the 2nd get\");\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_REJECTION);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    @Test\n    public void testExecutionSemaphoreWithQueue() throws Exception {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        // single thread should work\n        TestSemaphoreCommand command1 = new TestSemaphoreCommand(circuitBreaker, 1, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        boolean result = command1.queue().get();\n        assertTrue(result);\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TryableSemaphore semaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        final TestSemaphoreCommand command2 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    command2.queue().get();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n        final TestSemaphoreCommand command3 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r3 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    command3.queue().get();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore\n        Thread t2 = new Thread(r2);\n        Thread t3 = new Thread(r3);\n\n        t2.start();\n        // make sure that t2 gets a chance to run before queuing the next one\n        Thread.sleep(50);\n        t3.start();\n        t2.join();\n        t3.join();\n\n        if (!exceptionReceived.get()) {\n            fail(\"We expected an exception on the 2nd get\");\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    @Test\n    public void testExecutionSemaphoreWithExecution() throws Exception {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        // single thread should work\n        TestSemaphoreCommand command1 = new TestSemaphoreCommand(circuitBreaker, 1, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        boolean result = command1.execute();\n        assertFalse(command1.isExecutedInThread());\n        assertTrue(result);\n\n        final ArrayBlockingQueue<Boolean> results = new ArrayBlockingQueue<Boolean>(2);\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TryableSemaphore semaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        final TestSemaphoreCommand command2 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command2.execute());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n        final TestSemaphoreCommand command3 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r3 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command3.execute());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore\n        Thread t2 = new Thread(r2);\n        Thread t3 = new Thread(r3);\n\n        t2.start();\n        // make sure that t2 gets a chance to run before queuing the next one\n        Thread.sleep(50);\n        t3.start();\n        t2.join();\n        t3.join();\n\n        if (!exceptionReceived.get()) {\n            fail(\"We expected an exception on the 2nd get\");\n        }\n\n        // only 1 value is expected as the other should have thrown an exception\n        assertEquals(1, results.size());\n        // should contain only a true result\n        assertTrue(results.contains(Boolean.TRUE));\n        assertFalse(results.contains(Boolean.FALSE));\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    @Test\n    public void testRejectedExecutionSemaphoreWithFallbackViaExecute() throws Exception {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        final ArrayBlockingQueue<Boolean> results = new ArrayBlockingQueue<Boolean>(2);\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TestSemaphoreCommandWithFallback command1 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r1 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command1.execute());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        final TestSemaphoreCommandWithFallback command2 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command2.execute());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore and return fallback\n        Thread t1 = new Thread(r1);\n        Thread t2 = new Thread(r2);\n\n        t1.start();\n        // make sure that t2 gets a chance to run before queuing the next one\n        Thread.sleep(50);\n        t2.start();\n        t1.join();\n        t2.join();\n\n        if (exceptionReceived.get()) {\n            fail(\"We should have received a fallback response\");\n        }\n\n        // both threads should have returned values\n        assertEquals(2, results.size());\n        // should contain both a true and false result\n        assertTrue(results.contains(Boolean.TRUE));\n        assertTrue(results.contains(Boolean.FALSE));\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testRejectedExecutionSemaphoreWithFallbackViaObserve() throws Exception {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        final ArrayBlockingQueue<Observable<Boolean>> results = new ArrayBlockingQueue<Observable<Boolean>>(2);\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TestSemaphoreCommandWithFallback command1 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r1 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command1.observe());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        final TestSemaphoreCommandWithFallback command2 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command2.observe());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore and return fallback\n        Thread t1 = new Thread(r1);\n        Thread t2 = new Thread(r2);\n\n        t1.start();\n        // make sure that t2 gets a chance to run before queuing the next one\n        Thread.sleep(50);\n        t2.start();\n        t1.join();\n        t2.join();\n\n        if (exceptionReceived.get()) {\n            fail(\"We should have received a fallback response\");\n        }\n\n        final List<Boolean> blockingList = Observable.merge(results).toList().toBlocking().single();\n\n        // both threads should have returned values\n        assertEquals(2, blockingList.size());\n        // should contain both a true and false result\n        assertTrue(blockingList.contains(Boolean.TRUE));\n        assertTrue(blockingList.contains(Boolean.FALSE));\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Tests that semaphores are counted separately for commands with unique keys\n     */\n    @Test\n    public void testSemaphorePermitsInUse() throws Exception {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        // this semaphore will be shared across multiple command instances\n        final TryableSemaphoreActual sharedSemaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(3));\n\n        // used to wait until all commands have started\n        final CountDownLatch startLatch = new CountDownLatch((sharedSemaphore.numberOfPermits.get() * 2) + 1);\n\n        // used to signal that all command can finish\n        final CountDownLatch sharedLatch = new CountDownLatch(1);\n\n        // tracks failures to obtain semaphores\n        final AtomicInteger failureCount = new AtomicInteger();\n\n        final Runnable sharedSemaphoreRunnable = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n            public void run() {\n                try {\n                    new LatchedSemaphoreCommand(\"Command-Shared\", circuitBreaker, sharedSemaphore, startLatch, sharedLatch).execute();\n                } catch (Exception e) {\n                    startLatch.countDown();\n                    e.printStackTrace();\n                    failureCount.incrementAndGet();\n                }\n            }\n        });\n\n        // creates group of threads each using command sharing a single semaphore\n        // I create extra threads and commands so that I can verify that some of them fail to obtain a semaphore\n        final int sharedThreadCount = sharedSemaphore.numberOfPermits.get() * 2;\n        final Thread[] sharedSemaphoreThreads = new Thread[sharedThreadCount];\n        for (int i = 0; i < sharedThreadCount; i++) {\n            sharedSemaphoreThreads[i] = new Thread(sharedSemaphoreRunnable);\n        }\n\n        // creates thread using isolated semaphore\n        final TryableSemaphoreActual isolatedSemaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        final CountDownLatch isolatedLatch = new CountDownLatch(1);\n\n        final Thread isolatedThread = new Thread(new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n            public void run() {\n                try {\n                    new LatchedSemaphoreCommand(\"Command-Isolated\", circuitBreaker, isolatedSemaphore, startLatch, isolatedLatch).execute();\n                } catch (Exception e) {\n                    startLatch.countDown();\n                    e.printStackTrace();\n                    failureCount.incrementAndGet();\n                }\n            }\n        }));\n\n        // verifies no permits in use before starting threads\n        assertEquals(\"before threads start, shared semaphore should be unused\", 0, sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"before threads start, isolated semaphore should be unused\", 0, isolatedSemaphore.getNumberOfPermitsUsed());\n\n        for (int i = 0; i < sharedThreadCount; i++) {\n            sharedSemaphoreThreads[i].start();\n        }\n        isolatedThread.start();\n\n        // waits until all commands have started\n        startLatch.await(1000, TimeUnit.MILLISECONDS);\n\n        // verifies that all semaphores are in use\n        assertEquals(\"immediately after command start, all shared semaphores should be in-use\",\n                sharedSemaphore.numberOfPermits.get().longValue(), sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"immediately after command start, isolated semaphore should be in-use\",\n                isolatedSemaphore.numberOfPermits.get().longValue(), isolatedSemaphore.getNumberOfPermitsUsed());\n\n        // signals commands to finish\n        sharedLatch.countDown();\n        isolatedLatch.countDown();\n\n        for (int i = 0; i < sharedThreadCount; i++) {\n            sharedSemaphoreThreads[i].join();\n        }\n        isolatedThread.join();\n\n        // verifies no permits in use after finishing threads\n        System.out.println(\"REQLOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n        assertEquals(\"after all threads have finished, no shared semaphores should be in-use\", 0, sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"after all threads have finished, isolated semaphore not in-use\", 0, isolatedSemaphore.getNumberOfPermitsUsed());\n\n        // verifies that some executions failed\n        assertEquals(\"expected some of shared semaphore commands to get rejected\", sharedSemaphore.numberOfPermits.get().longValue(), failureCount.get());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n    }\n\n    /**\n     * Test that HystrixOwner can be passed in dynamically.\n     */\n    @Test\n    public void testDynamicOwner() {\n        TestHystrixCommand<Boolean> command = new DynamicOwnerTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE);\n        assertEquals(true, command.execute());\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test(expected = IllegalStateException.class)\n    public void testDynamicOwnerFails() {\n        TestHystrixCommand<Boolean> command = new DynamicOwnerTestCommand(null);\n        assertEquals(true, command.execute());\n    }\n\n    /**\n     * Test that HystrixCommandKey can be passed in dynamically.\n     */\n    @Test\n    public void testDynamicKey() throws Exception {\n        DynamicOwnerAndKeyTestCommand command1 = new DynamicOwnerAndKeyTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE, InspectableBuilder.CommandKeyForUnitTest.KEY_ONE);\n        assertEquals(true, command1.execute());\n        DynamicOwnerAndKeyTestCommand command2 = new DynamicOwnerAndKeyTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE, InspectableBuilder.CommandKeyForUnitTest.KEY_TWO);\n        assertEquals(true, command2.execute());\n\n        // 2 different circuit breakers should be created\n        assertNotSame(command1.getCircuitBreaker(), command2.getCircuitBreaker());\n    }\n\n    /**\n     * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future\n     */\n    @Test\n    public void testRequestCache1() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"A\", f2.get());\n\n        assertTrue(command1.executed);\n        // the second one should not have executed as it should have received the cached value instead\n        assertFalse(command2.executed);\n        assertTrue(command1.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command1.isResponseFromCache());\n        assertTrue(command2.isResponseFromCache());\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test Request scoped caching doesn't prevent different ones from executing\n     */\n    @Test\n    public void testRequestCache2() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"B\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"B\", f2.get());\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        assertTrue(command2.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command2.isResponseFromCache());\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertNull(command1.getExecutionException());\n        assertFalse(command2.isResponseFromCache());\n        assertNull(command2.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testRequestCache3() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"B\");\n        SuccessfulCacheableCommand<String> command3 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"B\", f2.get());\n        assertEquals(\"A\", f3.get());\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // but the 3rd should come from cache\n        assertFalse(command3.executed);\n        assertTrue(command3.isResponseFromCache());\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future\n     */\n    @Test\n    public void testRequestCacheWithSlowExecution() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SlowCacheableCommand command1 = new SlowCacheableCommand(circuitBreaker, \"A\", 200);\n        SlowCacheableCommand command2 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n        SlowCacheableCommand command3 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n        SlowCacheableCommand command4 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n        Future<String> f4 = command4.queue();\n\n        assertEquals(\"A\", f2.get());\n        assertEquals(\"A\", f3.get());\n        assertEquals(\"A\", f4.get());\n        assertEquals(\"A\", f1.get());\n\n        assertTrue(command1.executed);\n        // the second one should not have executed as it should have received the cached value instead\n        assertFalse(command2.executed);\n        assertFalse(command3.executed);\n        assertFalse(command4.executed);\n\n        assertTrue(command1.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command1.isResponseFromCache());\n        assertTrue(command2.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command2.isResponseFromCache());\n        assertTrue(command3.isResponseFromCache());\n        assertTrue(command3.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command4.isResponseFromCache());\n        assertTrue(command4.getExecutionTimeInMilliseconds() == -1);\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command4, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n        System.out.println(\"HystrixRequestLog: \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testNoRequestCache3() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"B\");\n        SuccessfulCacheableCommand<String> command3 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"B\", f2.get());\n        assertEquals(\"A\", f3.get());\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // this should also execute since we disabled the cache\n        assertTrue(command3.executed);\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testRequestCacheViaQueueSemaphore1() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"B\");\n        SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"A\");\n\n        assertFalse(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"B\", f2.get());\n        assertEquals(\"A\", f3.get());\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // but the 3rd should come from cache\n        assertFalse(command3.executed);\n        assertTrue(command3.isResponseFromCache());\n        assertTrue(command3.getExecutionTimeInMilliseconds() == -1);\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testNoRequestCacheViaQueueSemaphore1() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"A\");\n        SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"B\");\n        SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"A\");\n\n        assertFalse(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.queue();\n        Future<String> f2 = command2.queue();\n        Future<String> f3 = command3.queue();\n\n        assertEquals(\"A\", f1.get());\n        assertEquals(\"B\", f2.get());\n        assertEquals(\"A\", f3.get());\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // this should also execute because caching is disabled\n        assertTrue(command3.executed);\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testRequestCacheViaExecuteSemaphore1() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"B\");\n        SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, \"A\");\n\n        assertFalse(command1.isCommandRunningInThread());\n\n        String f1 = command1.execute();\n        String f2 = command2.execute();\n        String f3 = command3.execute();\n\n        assertEquals(\"A\", f1);\n        assertEquals(\"B\", f2);\n        assertEquals(\"A\", f3);\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // but the 3rd should come from cache\n        assertFalse(command3.executed);\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testNoRequestCacheViaExecuteSemaphore1() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"A\");\n        SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"B\");\n        SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, \"A\");\n\n        assertFalse(command1.isCommandRunningInThread());\n\n        String f1 = command1.execute();\n        String f2 = command2.execute();\n        String f3 = command3.execute();\n\n        assertEquals(\"A\", f1);\n        assertEquals(\"B\", f2);\n        assertEquals(\"A\", f3);\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // this should also execute because caching is disabled\n        assertTrue(command3.executed);\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    @Test\n    public void testNoRequestCacheOnTimeoutThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        NoRequestCacheTimeoutWithoutFallback r1 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            System.out.println(\"r1 value: \" + r1.execute());\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r1.isResponseTimedOut());\n            // what we want\n        }\n\n        NoRequestCacheTimeoutWithoutFallback r2 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r2.execute();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r2.isResponseTimedOut());\n            // what we want\n        }\n\n        NoRequestCacheTimeoutWithoutFallback r3 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        Future<Boolean> f3 = r3.queue();\n        try {\n            f3.get();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            assertTrue(r3.isResponseTimedOut());\n            // what we want\n        }\n\n        Thread.sleep(500); // timeout on command is set to 200ms\n\n        NoRequestCacheTimeoutWithoutFallback r4 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r4.execute();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r4.isResponseTimedOut());\n            assertFalse(r4.isResponseFromFallback());\n            // what we want\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    @Test\n    public void testRequestCacheOnTimeoutCausesNullPointerException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        RequestCacheNullPointerExceptionCase command1 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command2 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command3 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n\n        // Expect it to time out - all results should be false\n        assertFalse(command1.execute());\n        assertFalse(command2.execute()); // return from cache #1\n        assertFalse(command3.execute()); // return from cache #2\n        Thread.sleep(500); // timeout on command is set to 200ms\n\n        RequestCacheNullPointerExceptionCase command4 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        Boolean value = command4.execute(); // return from cache #3\n        assertFalse(value);\n        RequestCacheNullPointerExceptionCase command5 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        Future<Boolean> f = command5.queue(); // return from cache #4\n        // the bug is that we're getting a null Future back, rather than a Future that returns false\n        assertNotNull(f);\n        assertFalse(f.get());\n\n        assertTrue(command5.isResponseFromFallback());\n        assertTrue(command5.isResponseTimedOut());\n        assertFalse(command5.isFailedExecution());\n        assertFalse(command5.isResponseShortCircuited());\n        assertNotNull(command5.getExecutionException());\n\n        assertCommandExecutionEvents(command1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command5, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(5);\n    }\n\n    @Test\n    public void testRequestCacheOnTimeoutThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        RequestCacheTimeoutWithoutFallback r1 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            System.out.println(\"r1 value: \" + r1.execute());\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r1.isResponseTimedOut());\n            // what we want\n        }\n\n        RequestCacheTimeoutWithoutFallback r2 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r2.execute();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r2.isResponseTimedOut());\n            // what we want\n        }\n\n        RequestCacheTimeoutWithoutFallback r3 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        Future<Boolean> f3 = r3.queue();\n        try {\n            f3.get();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            assertTrue(r3.isResponseTimedOut());\n            // what we want\n        }\n\n        Thread.sleep(500); // timeout on command is set to 200ms\n\n        RequestCacheTimeoutWithoutFallback r4 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r4.execute();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r4.isResponseTimedOut());\n            assertFalse(r4.isResponseFromFallback());\n            // what we want\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    @Test\n    public void testRequestCacheOnThreadRejectionThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CountDownLatch completionLatch = new CountDownLatch(1);\n        RequestCacheThreadRejectionWithoutFallback r1 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r1: \" + r1.execute());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r1.isResponseRejected());\n            // what we want\n        }\n\n        RequestCacheThreadRejectionWithoutFallback r2 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r2: \" + r2.execute());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            //                e.printStackTrace();\n            assertTrue(r2.isResponseRejected());\n            // what we want\n        }\n\n        RequestCacheThreadRejectionWithoutFallback r3 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"f3: \" + r3.queue().get());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            //                e.printStackTrace();\n            assertTrue(r3.isResponseRejected());\n            // what we want\n        }\n\n        // let the command finish (only 1 should actually be blocked on this due to the response cache)\n        completionLatch.countDown();\n\n        // then another after the command has completed\n        RequestCacheThreadRejectionWithoutFallback r4 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r4: \" + r4.execute());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            //                e.printStackTrace();\n            assertTrue(r4.isResponseRejected());\n            assertFalse(r4.isResponseFromFallback());\n            // what we want\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r3, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r4, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    /**\n     * Test that we can do basic execution without a RequestVariable being initialized.\n     */\n    @Test\n    public void testBasicExecutionWorksWithoutRequestVariable() throws Exception {\n        /* force the RequestVariable to not be initialized */\n        HystrixRequestContext.setContextOnCurrentThread(null);\n\n        TestHystrixCommand<Boolean> command = new SuccessfulTestCommand();\n        assertEquals(true, command.execute());\n\n        TestHystrixCommand<Boolean> command2 = new SuccessfulTestCommand();\n        assertEquals(true, command2.queue().get());\n    }\n\n    /**\n     * Test that if we try and execute a command with a cacheKey without initializing RequestVariable that it gives an error.\n     */\n    @Test(expected = HystrixRuntimeException.class)\n    public void testCacheKeyExecutionRequiresRequestVariable() throws Exception {\n        /* force the RequestVariable to not be initialized */\n        HystrixRequestContext.setContextOnCurrentThread(null);\n\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        SuccessfulCacheableCommand command = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"one\");\n        assertEquals(\"one\", command.execute());\n\n        SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"two\");\n        assertEquals(\"two\", command2.queue().get());\n    }\n\n    /**\n     * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testBadRequestExceptionViaExecuteInThread() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        BadRequestCommand command1 = null;\n        try {\n            command1 = new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD);\n            command1.execute();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (HystrixBadRequestException e) {\n            // success\n            e.printStackTrace();\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testBadRequestExceptionViaQueueInThread() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        BadRequestCommand command1 = null;\n        try {\n            command1 = new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD);\n            command1.queue().get();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            if (e.getCause() instanceof HystrixBadRequestException) {\n                // success\n            } else {\n                fail(\"We expect a \" + HystrixBadRequestException.class.getSimpleName() + \" but got a \" + e.getClass().getSimpleName());\n            }\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertNotNull(command1.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test that BadRequestException behavior works the same on a cached response.\n     */\n    @Test\n    public void testBadRequestExceptionViaQueueInThreadOnResponseFromCache() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        // execute once to cache the value\n        BadRequestCommand command1 = null;\n        try {\n            command1 = new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD);\n            command1.execute();\n        } catch (Throwable e) {\n            // ignore\n        }\n\n        BadRequestCommand command2 = null;\n        try {\n            command2 = new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD);\n            command2.queue().get();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            if (e.getCause() instanceof HystrixBadRequestException) {\n                // success\n            } else {\n                fail(\"We expect a \" + HystrixBadRequestException.class.getSimpleName() + \" but got a \" + e.getClass().getSimpleName());\n            }\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertCommandExecutionEvents(command2, HystrixEventType.BAD_REQUEST, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testBadRequestExceptionViaExecuteInSemaphore() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        BadRequestCommand command1 = new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE);\n        try {\n            command1.execute();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (HystrixBadRequestException e) {\n            // success\n            e.printStackTrace();\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a checked Exception being thrown\n     */\n    @Test\n    public void testCheckedExceptionViaExecute() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker);\n        try {\n            command.execute();\n            fail(\"we expect to receive a \" + Exception.class.getSimpleName());\n        } catch (Exception e) {\n            assertEquals(\"simulated checked exception message\", e.getCause().getMessage());\n        }\n\n        assertEquals(\"simulated checked exception message\", command.getFailedExecutionException().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a java.lang.Error being thrown\n     *\n     * @throws InterruptedException\n     */\n    @Test\n    public void testCheckedExceptionViaObserve() throws InterruptedException {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker);\n        final AtomicReference<Throwable> t = new AtomicReference<Throwable>();\n        final CountDownLatch latch = new CountDownLatch(1);\n        try {\n            command.observe().subscribe(new Observer<Boolean>() {\n\n                @Override\n                public void onCompleted() {\n                    latch.countDown();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    t.set(e);\n                    latch.countDown();\n                }\n\n                @Override\n                public void onNext(Boolean args) {\n\n                }\n\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"we should not get anything thrown, it should be emitted via the Observer#onError method\");\n        }\n\n        latch.await(1, TimeUnit.SECONDS);\n        assertNotNull(t.get());\n        t.get().printStackTrace();\n\n        assertTrue(t.get() instanceof HystrixRuntimeException);\n        assertEquals(\"simulated checked exception message\", t.get().getCause().getMessage());\n        assertEquals(\"simulated checked exception message\", command.getFailedExecutionException().getMessage());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test an Exception implementing NotWrappedByHystrix being thrown\n     *\n     * @throws InterruptedException\n     */\n    @Test\n    public void testNotWrappedExceptionViaObserve() throws InterruptedException {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithNotWrappedByHystrixException command = new CommandWithNotWrappedByHystrixException(circuitBreaker);\n        final AtomicReference<Throwable> t = new AtomicReference<Throwable>();\n        final CountDownLatch latch = new CountDownLatch(1);\n        try {\n            command.observe().subscribe(new Observer<Boolean>() {\n\n                @Override\n                public void onCompleted() {\n                    latch.countDown();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    t.set(e);\n                    latch.countDown();\n                }\n\n                @Override\n                public void onNext(Boolean args) {\n\n                }\n\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"we should not get anything thrown, it should be emitted via the Observer#onError method\");\n        }\n\n        latch.await(1, TimeUnit.SECONDS);\n        assertNotNull(t.get());\n        t.get().printStackTrace();\n\n        assertTrue(t.get() instanceof NotWrappedByHystrixTestException);\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertTrue(command.getExecutionException() instanceof NotWrappedByHystrixTestException);\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testSemaphoreExecutionWithTimeout() {\n        TestHystrixCommand<Boolean> cmd = new InterruptibleCommand(new TestCircuitBreaker(), false);\n\n        System.out.println(\"Starting command\");\n        long timeMillis = System.currentTimeMillis();\n        try {\n            cmd.execute();\n            fail(\"Should throw\");\n        } catch (Throwable t) {\n            assertNotNull(cmd.getExecutionException());\n\n            System.out.println(\"Unsuccessful Execution took : \" + (System.currentTimeMillis() - timeMillis));\n            assertCommandExecutionEvents(cmd, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n            assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n        }\n    }\n\n    /**\n     * Test a recoverable java.lang.Error being thrown with no fallback\n     */\n    @Test\n    public void testRecoverableErrorWithNoFallbackThrowsError() {\n        TestHystrixCommand<Integer> command = getRecoverableErrorCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we expect to receive a \" + Error.class.getSimpleName());\n        } catch (Exception e) {\n            // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public\n            // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x\n            // so HystrixRuntimeException -> wrapper Exception -> actual Error\n            assertEquals(\"Execution ERROR for TestHystrixCommand\", e.getCause().getCause().getMessage());\n        }\n\n        assertEquals(\"Execution ERROR for TestHystrixCommand\", command.getFailedExecutionException().getCause().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testRecoverableErrorMaskedByFallbackButLogged() {\n        TestHystrixCommand<Integer> command = getRecoverableErrorCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        assertEquals(FlexibleTestHystrixCommand.FALLBACK_VALUE, command.execute());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testUnrecoverableErrorThrownWithNoFallback() {\n        TestHystrixCommand<Integer> command = getUnrecoverableErrorCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n        try {\n            command.execute();\n            fail(\"we expect to receive a \" + Error.class.getSimpleName());\n        } catch (Exception e) {\n            // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public\n            // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x\n            // so HystrixRuntimeException -> wrapper Exception -> actual Error\n            assertEquals(\"Unrecoverable Error for TestHystrixCommand\", e.getCause().getCause().getMessage());\n        }\n\n        assertEquals(\"Unrecoverable Error for TestHystrixCommand\", command.getFailedExecutionException().getCause().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test //even though fallback is implemented, that logic never fires, as this is an unrecoverable error and should be directly propagated to the caller\n    public void testUnrecoverableErrorThrownWithFallback() {\n        TestHystrixCommand<Integer> command = getUnrecoverableErrorCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n        try {\n            command.execute();\n            fail(\"we expect to receive a \" + Error.class.getSimpleName());\n        } catch (Exception e) {\n            // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public\n            // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x\n            // so HystrixRuntimeException -> wrapper Exception -> actual Error\n            assertEquals(\"Unrecoverable Error for TestHystrixCommand\", e.getCause().getCause().getMessage());\n        }\n\n        assertEquals(\"Unrecoverable Error for TestHystrixCommand\", command.getFailedExecutionException().getCause().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    static class EventCommand extends HystrixCommand {\n        public EventCommand() {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"eventGroup\")).andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withFallbackIsolationSemaphoreMaxConcurrentRequests(3)));\n        }\n\n        @Override\n        protected String run() throws Exception {\n            System.out.println(Thread.currentThread().getName() + \" : In run()\");\n            throw new RuntimeException(\"run_exception\");\n        }\n\n        @Override\n        public String getFallback() {\n            try {\n                System.out.println(Thread.currentThread().getName() + \" : In fallback => \" + getExecutionEvents());\n                Thread.sleep(30000L);\n            } catch (InterruptedException e) {\n                System.out.println(Thread.currentThread().getName() + \" : Interruption occurred\");\n            }\n            System.out.println(Thread.currentThread().getName() + \" : CMD Success Result\");\n            return \"fallback\";\n        }\n    }\n\n    @Test\n    public void testNonBlockingCommandQueueFiresTimeout() throws Exception { //see https://github.com/Netflix/Hystrix/issues/514\n        final TestHystrixCommand<Integer> cmd = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n\n        new Thread() {\n            @Override\n            public void run() {\n                cmd.queue();\n            }\n        }.start();\n\n        Thread.sleep(200);\n        //timeout should occur in 50ms, and underlying thread should run for 500ms\n        //therefore, after 200ms, the command should have finished with a fallback on timeout\n\n        assertTrue(cmd.isExecutionComplete());\n        assertTrue(cmd.isResponseTimedOut());\n\n        assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());\n    }\n\n    @Override\n    protected void assertHooksOnSuccess(Func0<TestHystrixCommand<Integer>> ctor, Action1<TestHystrixCommand<Integer>> assertion) {\n        assertExecute(ctor.call(), assertion, true);\n        assertBlockingQueue(ctor.call(), assertion, true);\n        assertNonBlockingQueue(ctor.call(), assertion, true, false);\n        assertBlockingObserve(ctor.call(), assertion, true);\n        assertNonBlockingObserve(ctor.call(), assertion, true);\n    }\n\n    @Override\n    protected void assertHooksOnFailure(Func0<TestHystrixCommand<Integer>> ctor, Action1<TestHystrixCommand<Integer>> assertion) {\n        assertExecute(ctor.call(), assertion, false);\n        assertBlockingQueue(ctor.call(), assertion, false);\n        assertNonBlockingQueue(ctor.call(), assertion, false, false);\n        assertBlockingObserve(ctor.call(), assertion, false);\n        assertNonBlockingObserve(ctor.call(), assertion, false);\n    }\n\n    @Override\n    protected void assertHooksOnFailure(Func0<TestHystrixCommand<Integer>> ctor, Action1<TestHystrixCommand<Integer>> assertion, boolean failFast) {\n        assertExecute(ctor.call(), assertion, false);\n        assertBlockingQueue(ctor.call(), assertion, false);\n        assertNonBlockingQueue(ctor.call(), assertion, false, failFast);\n        assertBlockingObserve(ctor.call(), assertion, false);\n        assertNonBlockingObserve(ctor.call(), assertion, false);\n    }\n\n    /**\n     * Run the command via {@link com.netflix.hystrix.HystrixCommand#execute()} and then assert\n     * @param command command to run\n     * @param assertion assertions to check\n     * @param isSuccess should the command succeedInteger\n     */\n    private void assertExecute(TestHystrixCommand<Integer> command, Action1<TestHystrixCommand<Integer>> assertion, boolean isSuccess) {\n        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Running command.execute() and then assertions...\");\n        if (isSuccess) {\n            command.execute();\n        } else {\n            try {\n                Object o = command.execute();\n                fail(\"Expected a command failure!\");\n            } catch (Exception ex) {\n                System.out.println(\"Received expected ex : \" + ex);\n                ex.printStackTrace();\n            }\n        }\n\n        assertion.call(command);\n    }\n\n    /**\n     * Run the command via {@link com.netflix.hystrix.HystrixCommand#queue()}, immediately block, and then assert\n     * @param command command to run\n     * @param assertion assertions to check\n     * @param isSuccess should the command succeedInteger\n     */\n    private void assertBlockingQueue(TestHystrixCommand<Integer> command, Action1<TestHystrixCommand<Integer>> assertion, boolean isSuccess) {\n        System.out.println(\"Running command.queue(), immediately blocking and then running assertions...\");\n        if (isSuccess) {\n            try {\n                command.queue().get();\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        } else {\n            try {\n                command.queue().get();\n                fail(\"Expected a command failure!\");\n            } catch (InterruptedException ie) {\n                throw new RuntimeException(ie);\n            } catch (ExecutionException ee) {\n                System.out.println(\"Received expected ex : \" + ee.getCause());\n                ee.getCause().printStackTrace();\n            } catch (Exception e) {\n                System.out.println(\"Received expected ex : \" + e);\n                e.printStackTrace();\n            }\n        }\n\n        assertion.call(command);\n    }\n\n    /**\n     * Run the command via {@link com.netflix.hystrix.HystrixCommand#queue()}, then poll for the command to be finished.\n     * When it is finished, assert\n     * @param command command to run\n     * @param assertion assertions to check\n     * @param isSuccess should the command succeedInteger\n     */\n    private void assertNonBlockingQueue(TestHystrixCommand<Integer> command, Action1<TestHystrixCommand<Integer>> assertion, boolean isSuccess, boolean failFast) {\n        System.out.println(\"Running command.queue(), sleeping the test thread until command is complete, and then running assertions...\");\n        Future<Integer> f = null;\n        if (failFast) {\n            try {\n                f = command.queue();\n                fail(\"Expected a failure when queuing the command\");\n            } catch (Exception ex) {\n                System.out.println(\"Received expected fail fast ex : \" + ex);\n                ex.printStackTrace();\n            }\n        } else {\n            try {\n                f = command.queue();\n            } catch (Exception ex) {\n                throw new RuntimeException(ex);\n            }\n        }\n        awaitCommandCompletion(command);\n\n        assertion.call(command);\n\n        if (isSuccess) {\n            try {\n                f.get();\n            } catch (Exception ex) {\n                throw new RuntimeException(ex);\n            }\n        } else {\n            try {\n                f.get();\n                fail(\"Expected a command failure!\");\n            } catch (InterruptedException ie) {\n                throw new RuntimeException(ie);\n            } catch (ExecutionException ee) {\n                System.out.println(\"Received expected ex : \" + ee.getCause());\n                ee.getCause().printStackTrace();\n            } catch (Exception e) {\n                System.out.println(\"Received expected ex : \" + e);\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private <T> void awaitCommandCompletion(TestHystrixCommand<T> command) {\n        while (!command.isExecutionComplete()) {\n            try {\n                Thread.sleep(10);\n            } catch (InterruptedException e) {\n                throw new RuntimeException(\"interrupted\");\n            }\n        }\n    }\n\n    /**\n     * Test a command execution that fails but has a fallback.\n     */\n    @Test\n    public void testExecutionFailureWithFallbackImplementedButDisabled() {\n        TestHystrixCommand<Boolean> commandEnabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), true);\n        try {\n            assertEquals(false, commandEnabled.execute());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        TestHystrixCommand<Boolean> commandDisabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), false);\n        try {\n            assertEquals(false, commandDisabled.execute());\n            fail(\"expect exception thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        assertEquals(\"we failed with a simulated issue\", commandDisabled.getFailedExecutionException().getMessage());\n\n        assertTrue(commandDisabled.isFailedExecution());\n        assertCommandExecutionEvents(commandEnabled, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(commandDisabled, HystrixEventType.FAILURE);\n        assertNotNull(commandDisabled.getExecutionException());\n        assertEquals(0, commandDisabled.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testExecutionTimeoutValue() {\n        HystrixCommand.Setter properties = HystrixCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestKey\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionTimeoutInMilliseconds(50));\n\n        HystrixCommand<String> command = new HystrixCommand<String>(properties) {\n            @Override\n            protected String run() throws Exception {\n                Thread.sleep(3000);\n                // should never reach here\n                return \"hello\";\n            }\n\n            @Override\n            protected String getFallback() {\n                if (isResponseTimedOut()) {\n                    return \"timed-out\";\n                } else {\n                    return \"abc\";\n                }\n            }\n        };\n\n        String value = command.execute();\n        assertTrue(command.isResponseTimedOut());\n        assertEquals(\"expected fallback value\", \"timed-out\", value);\n\n    }\n\n    /**\n     * See https://github.com/Netflix/Hystrix/issues/212\n     */\n    @Test\n    public void testObservableTimeoutNoFallbackThreadContext() {\n        TestSubscriber<Object> ts = new TestSubscriber<Object>();\n\n        final AtomicReference<Thread> onErrorThread = new AtomicReference<Thread>();\n        final AtomicBoolean isRequestContextInitialized = new AtomicBoolean();\n\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 50);\n        command.toObservable().doOnError(new Action1<Throwable>() {\n\n            @Override\n            public void call(Throwable t1) {\n                System.out.println(\"onError: \" + t1);\n                System.out.println(\"onError Thread: \" + Thread.currentThread());\n                System.out.println(\"ThreadContext in onError: \" + HystrixRequestContext.isCurrentThreadInitialized());\n                onErrorThread.set(Thread.currentThread());\n                isRequestContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n            }\n\n        }).subscribe(ts);\n\n        ts.awaitTerminalEvent();\n\n        assertTrue(isRequestContextInitialized.get());\n        assertTrue(onErrorThread.get().getName().startsWith(\"HystrixTimer\"));\n\n        List<Throwable> errors = ts.getOnErrorEvents();\n        assertEquals(1, errors.size());\n        Throwable e = errors.get(0);\n        if (errors.get(0) instanceof HystrixRuntimeException) {\n            HystrixRuntimeException de = (HystrixRuntimeException) e;\n            assertNotNull(de.getFallbackException());\n            assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n            assertNotNull(de.getImplementingClass());\n            assertNotNull(de.getCause());\n            assertTrue(de.getCause() instanceof TimeoutException);\n        } else {\n            fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, command.getBuilder().metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testExceptionConvertedToBadRequestExceptionInExecutionHookBypassesCircuitBreaker() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        ExceptionToBadRequestByExecutionHookCommand command =  new ExceptionToBadRequestByExecutionHookCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD);\n        try {\n            command.execute();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (HystrixBadRequestException e) {\n            // success\n            e.printStackTrace();\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We expect a \" + HystrixBadRequestException.class.getSimpleName() + \" but got a \" + e.getClass().getSimpleName());\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.BAD_REQUEST);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testInterruptFutureOnTimeout() throws InterruptedException, ExecutionException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true);\n\n        // when\n        Future<Boolean> f = cmd.queue();\n\n        // then\n        Thread.sleep(500);\n        assertTrue(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testInterruptObserveOnTimeout() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true);\n\n        // when\n        cmd.observe().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertTrue(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testInterruptToObservableOnTimeout() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true);\n\n        // when\n        cmd.toObservable().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertTrue(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testDoNotInterruptFutureOnTimeoutIfPropertySaysNotTo() throws InterruptedException, ExecutionException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), false);\n\n        // when\n        Future<Boolean> f = cmd.queue();\n\n        // then\n        Thread.sleep(500);\n        assertFalse(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testDoNotInterruptObserveOnTimeoutIfPropertySaysNotTo() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), false);\n\n        // when\n        cmd.observe().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertFalse(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testDoNotInterruptToObservableOnTimeoutIfPropertySaysNotTo() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), false);\n\n        // when\n        cmd.toObservable().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertFalse(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testCancelFutureWithInterruptionWhenPropertySaysNotTo() throws InterruptedException, ExecutionException {\n    \t// given\n    \tInterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true, false, 1000);\n\n        // when\n        Future<Boolean> f = cmd.queue();\n        Thread.sleep(500);\n        f.cancel(true);\n        Thread.sleep(500);\n\n        // then\n        try {\n        \tf.get();\n        \tfail(\"Should have thrown a CancellationException\");\n        } catch (CancellationException e) {\n        \tassertFalse(cmd.hasBeenInterrupted());\n        }\n    }\n\n    @Test\n    public void testCancelFutureWithInterruption() throws InterruptedException, ExecutionException {\n    \t// given\n    \tInterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true, true, 1000);\n\n        // when\n        Future<Boolean> f = cmd.queue();\n        Thread.sleep(500);\n        f.cancel(true);\n        Thread.sleep(500);\n\n        // then\n        try {\n        \tf.get();\n        \tfail(\"Should have thrown a CancellationException\");\n        } catch (CancellationException e) {\n        \tassertTrue(cmd.hasBeenInterrupted());\n        }\n    }\n\n    @Test\n    public void testCancelFutureWithoutInterruption() throws InterruptedException, ExecutionException, TimeoutException {\n    \t// given\n    \tInterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true, true, 1000);\n\n        // when\n        Future<Boolean> f = cmd.queue();\n        Thread.sleep(500);\n        f.cancel(false);\n        Thread.sleep(500);\n\n        // then\n        try {\n        \tf.get();\n        \tfail(\"Should have thrown a CancellationException\");\n        } catch (CancellationException e) {\n        \tassertFalse(cmd.hasBeenInterrupted());\n        }\n    }\n\n    @Test\n    public void testChainedCommand() {\n        class SubCommand extends TestHystrixCommand<Integer> {\n\n            public SubCommand(TestCircuitBreaker circuitBreaker) {\n                super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            }\n\n            @Override\n            protected Integer run() throws Exception {\n                return 2;\n            }\n        }\n\n        class PrimaryCommand extends TestHystrixCommand<Integer> {\n            public PrimaryCommand(TestCircuitBreaker circuitBreaker) {\n                super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            }\n\n            @Override\n            protected Integer run() throws Exception {\n                throw new RuntimeException(\"primary failure\");\n            }\n\n            @Override\n            protected Integer getFallback() {\n                SubCommand subCmd = new SubCommand(new TestCircuitBreaker());\n                return subCmd.execute();\n            }\n        }\n\n        assertTrue(2 == new PrimaryCommand(new TestCircuitBreaker()).execute());\n    }\n\n    @Test\n    public void testSlowFallback() {\n        class PrimaryCommand extends TestHystrixCommand<Integer> {\n            public PrimaryCommand(TestCircuitBreaker circuitBreaker) {\n                super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            }\n\n            @Override\n            protected Integer run() throws Exception {\n                throw new RuntimeException(\"primary failure\");\n            }\n\n            @Override\n            protected Integer getFallback() {\n                try {\n                    Thread.sleep(1500);\n                    return 1;\n                } catch (InterruptedException ie) {\n                    System.out.println(\"Caught Interrupted Exception\");\n                    ie.printStackTrace();\n                }\n                return -1;\n            }\n        }\n\n        assertTrue(1 == new PrimaryCommand(new TestCircuitBreaker()).execute());\n    }\n\n    @Test\n    public void testSemaphoreThreadSafety() {\n        final int NUM_PERMITS = 1;\n        final TryableSemaphoreActual s = new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(NUM_PERMITS));\n\n        final int NUM_THREADS = 10;\n        ExecutorService threadPool = Executors.newFixedThreadPool(NUM_THREADS);\n\n        final int NUM_TRIALS = 100;\n\n        for (int t = 0; t < NUM_TRIALS; t++) {\n\n            System.out.println(\"TRIAL : \" + t);\n\n            final AtomicInteger numAcquired = new AtomicInteger(0);\n            final CountDownLatch latch = new CountDownLatch(NUM_THREADS);\n\n            for (int i = 0; i < NUM_THREADS; i++) {\n                threadPool.submit(new Runnable() {\n                    @Override\n                    public void run() {\n                        boolean acquired = s.tryAcquire();\n                        if (acquired) {\n                            try {\n                                numAcquired.incrementAndGet();\n                                Thread.sleep(100);\n                            } catch (InterruptedException ex) {\n                                ex.printStackTrace();\n                            } finally {\n                                s.release();\n                            }\n                        }\n                        latch.countDown();\n                    }\n                });\n            }\n\n            try {\n                assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n            } catch (InterruptedException ex) {\n                fail(ex.getMessage());\n            }\n\n            assertEquals(\"Number acquired should be equal to the number of permits\", NUM_PERMITS, numAcquired.get());\n            assertEquals(\"Semaphore should always get released back to 0\", 0, s.getNumberOfPermitsUsed());\n        }\n    }\n\n    @Test\n    public void testCancelledTasksInQueueGetRemoved() throws Exception {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cancellation-A\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SingleThreadedPoolWithQueue pool = new SingleThreadedPoolWithQueue(10, 1);\n        TestCommandRejection command1 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_NOT_IMPLEMENTED);\n        TestCommandRejection command2 = new TestCommandRejection(key, circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_NOT_IMPLEMENTED);\n\n        // this should go through the queue and into the thread pool\n        Future<Boolean> poolFiller = command1.queue();\n        // this command will stay in the queue until the thread pool is empty\n        Observable<Boolean> cmdInQueue = command2.observe();\n        Subscription s = cmdInQueue.subscribe();\n        assertEquals(1, pool.queue.size());\n        s.unsubscribe();\n        assertEquals(0, pool.queue.size());\n        //make sure we wait for the command to finish so the state is clean for next test\n        poolFiller.get();\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.CANCELLED);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testOnRunStartHookThrowsSemaphoreIsolated() {\n        final AtomicBoolean exceptionEncountered = new AtomicBoolean(false);\n        final AtomicBoolean onThreadStartInvoked = new AtomicBoolean(false);\n        final AtomicBoolean onThreadCompleteInvoked = new AtomicBoolean(false);\n        final AtomicBoolean executionAttempted = new AtomicBoolean(false);\n\n        class FailureInjectionHook extends HystrixCommandExecutionHook {\n            @Override\n            public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {\n                throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION, commandInstance.getClass(), \"Injected Failure\", null, null);\n            }\n\n            @Override\n            public <T> void onThreadStart(HystrixInvokable<T> commandInstance) {\n                onThreadStartInvoked.set(true);\n                super.onThreadStart(commandInstance);\n            }\n\n            @Override\n            public <T> void onThreadComplete(HystrixInvokable<T> commandInstance) {\n                onThreadCompleteInvoked.set(true);\n                super.onThreadComplete(commandInstance);\n            }\n        }\n\n        final FailureInjectionHook failureInjectionHook = new FailureInjectionHook();\n\n        class FailureInjectedCommand extends TestHystrixCommand<Integer> {\n            public FailureInjectedCommand(ExecutionIsolationStrategy isolationStrategy) {\n                super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy)), failureInjectionHook);\n            }\n\n            @Override\n            protected Integer run() throws Exception {\n                executionAttempted.set(true);\n                return 3;\n            }\n        }\n\n        TestHystrixCommand<Integer> semaphoreCmd = new FailureInjectedCommand(ExecutionIsolationStrategy.SEMAPHORE);\n        try {\n            int result = semaphoreCmd.execute();\n            System.out.println(\"RESULT : \" + result);\n        } catch (Throwable ex) {\n            ex.printStackTrace();\n            exceptionEncountered.set(true);\n        }\n        assertTrue(exceptionEncountered.get());\n        assertFalse(onThreadStartInvoked.get());\n        assertFalse(onThreadCompleteInvoked.get());\n        assertFalse(executionAttempted.get());\n        assertEquals(0, semaphoreCmd.metrics.getCurrentConcurrentExecutionCount());\n\n    }\n\n    @Test\n    public void testOnRunStartHookThrowsThreadIsolated() {\n        final AtomicBoolean exceptionEncountered = new AtomicBoolean(false);\n        final AtomicBoolean onThreadStartInvoked = new AtomicBoolean(false);\n        final AtomicBoolean onThreadCompleteInvoked = new AtomicBoolean(false);\n        final AtomicBoolean executionAttempted = new AtomicBoolean(false);\n\n        class FailureInjectionHook extends HystrixCommandExecutionHook {\n            @Override\n            public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {\n                throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION, commandInstance.getClass(), \"Injected Failure\", null, null);\n            }\n\n            @Override\n            public <T> void onThreadStart(HystrixInvokable<T> commandInstance) {\n                onThreadStartInvoked.set(true);\n                super.onThreadStart(commandInstance);\n            }\n\n            @Override\n            public <T> void onThreadComplete(HystrixInvokable<T> commandInstance) {\n                onThreadCompleteInvoked.set(true);\n                super.onThreadComplete(commandInstance);\n            }\n        }\n\n        final FailureInjectionHook failureInjectionHook = new FailureInjectionHook();\n\n        class FailureInjectedCommand extends TestHystrixCommand<Integer> {\n            public FailureInjectedCommand(ExecutionIsolationStrategy isolationStrategy) {\n                super(testPropsBuilder(new TestCircuitBreaker()).setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy)), failureInjectionHook);\n            }\n\n            @Override\n            protected Integer run() throws Exception {\n                executionAttempted.set(true);\n                return 3;\n            }\n        }\n\n        TestHystrixCommand<Integer> threadCmd = new FailureInjectedCommand(ExecutionIsolationStrategy.THREAD);\n        try {\n            int result = threadCmd.execute();\n            System.out.println(\"RESULT : \" + result);\n        } catch (Throwable ex) {\n            ex.printStackTrace();\n            exceptionEncountered.set(true);\n        }\n        assertTrue(exceptionEncountered.get());\n        assertTrue(onThreadStartInvoked.get());\n        assertTrue(onThreadCompleteInvoked.get());\n        assertFalse(executionAttempted.get());\n        assertEquals(0, threadCmd.metrics.getCurrentConcurrentExecutionCount());\n\n    }\n\n    @Test\n    public void testEarlyUnsubscribeDuringExecutionViaToObservable() {\n        class AsyncCommand extends HystrixCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Boolean run() {\n                try {\n                    Thread.sleep(500);\n                    return true;\n                } catch (InterruptedException ex) {\n                    throw new RuntimeException(ex);\n                }\n            }\n        }\n\n        HystrixCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.toObservable();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            Thread.sleep(10);\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(cmd.isExecutionComplete());\n            assertEquals(null, cmd.getFailedExecutionException());\n            assertNull(cmd.getExecutionException());\n            System.out.println(\"Execution time : \" + cmd.getExecutionTimeInMilliseconds());\n            assertTrue(cmd.getExecutionTimeInMilliseconds() > -1);\n            assertFalse(cmd.isSuccessfulExecution());\n            assertCommandExecutionEvents(cmd, HystrixEventType.CANCELLED);\n            assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testEarlyUnsubscribeDuringExecutionViaObserve() {\n        class AsyncCommand extends HystrixCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Boolean run() {\n                try {\n                    Thread.sleep(500);\n                    return true;\n                } catch (InterruptedException ex) {\n                    throw new RuntimeException(ex);\n                }\n            }\n        }\n\n        HystrixCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.observe();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            Thread.sleep(10);\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(cmd.isExecutionComplete());\n            assertEquals(null, cmd.getFailedExecutionException());\n            assertNull(cmd.getExecutionException());\n            assertTrue(cmd.getExecutionTimeInMilliseconds() > -1);\n            assertFalse(cmd.isSuccessfulExecution());\n            assertCommandExecutionEvents(cmd, HystrixEventType.CANCELLED);\n            assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testEarlyUnsubscribeDuringFallback() {\n        class AsyncCommand extends HystrixCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Boolean run() {\n                throw new RuntimeException(\"run failure\");\n            }\n\n            @Override\n            protected Boolean getFallback() {\n                try {\n                    Thread.sleep(500);\n                    return false;\n                } catch (InterruptedException ex) {\n                    throw new RuntimeException(ex);\n                }\n            }\n        }\n\n        HystrixCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.toObservable();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            Thread.sleep(10); //give fallback a chance to fire\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());\n            assertFalse(cmd.isExecutionComplete());\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndCacheHitUnsubscribed() {\n        AsyncCacheableCommand original = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache = new AsyncCacheableCommand(\"foo\");\n\n        final AtomicReference<Boolean> originalValue = new AtomicReference<Boolean>(null);\n        final AtomicReference<Boolean> fromCacheValue = new AtomicReference<Boolean>(null);\n\n        final CountDownLatch originalLatch = new CountDownLatch(1);\n        final CountDownLatch fromCacheLatch = new CountDownLatch(1);\n\n        Observable<Boolean> originalObservable = original.toObservable();\n        Observable<Boolean> fromCacheObservable = fromCache.toObservable();\n\n        Subscription originalSubscription = originalObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original Unsubscribe\");\n                originalLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnCompleted\");\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnError : \" + e);\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnNext : \" + b);\n                originalValue.set(b);\n            }\n        });\n\n        Subscription fromCacheSubscription = fromCacheObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" FromCache Unsubscribe\");\n                fromCacheLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" FromCache OnCompleted\");\n                fromCacheLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" FromCache OnError : \" + e);\n                fromCacheLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" FromCache OnNext : \" + b);\n                fromCacheValue.set(b);\n            }\n        });\n\n        try {\n            fromCacheSubscription.unsubscribe();\n            assertTrue(fromCacheLatch.await(600, TimeUnit.MILLISECONDS));\n            assertTrue(originalLatch.await(600, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use (original)\", 0, original.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (original)\", 0, original.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertTrue(original.isExecutionComplete());\n            assertTrue(original.isExecutedInThread());\n            assertEquals(null, original.getFailedExecutionException());\n            assertNull(original.getExecutionException());\n            assertTrue(original.getExecutionTimeInMilliseconds() > -1);\n            assertTrue(original.isSuccessfulExecution());\n            assertCommandExecutionEvents(original, HystrixEventType.SUCCESS);\n            assertTrue(originalValue.get());\n            assertEquals(0, original.metrics.getCurrentConcurrentExecutionCount());\n\n\n            assertEquals(\"Number of execution semaphores in use (fromCache)\", 0, fromCache.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache)\", 0, fromCache.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(fromCache.isExecutionComplete());\n            assertFalse(fromCache.isExecutedInThread());\n            assertEquals(null, fromCache.getFailedExecutionException());\n            assertNull(fromCache.getExecutionException());\n            assertCommandExecutionEvents(fromCache, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);\n            assertTrue(fromCache.getExecutionTimeInMilliseconds() == -1);\n            assertFalse(fromCache.isSuccessfulExecution());\n            assertEquals(0, fromCache.metrics.getCurrentConcurrentExecutionCount());\n\n            assertFalse(original.isCancelled());  //underlying work\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            assertSaneHystrixRequestLog(2);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndOriginalUnsubscribed() {\n        AsyncCacheableCommand original = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache = new AsyncCacheableCommand(\"foo\");\n\n        final AtomicReference<Boolean> originalValue = new AtomicReference<Boolean>(null);\n        final AtomicReference<Boolean> fromCacheValue = new AtomicReference<Boolean>(null);\n\n        final CountDownLatch originalLatch = new CountDownLatch(1);\n        final CountDownLatch fromCacheLatch = new CountDownLatch(1);\n\n        Observable<Boolean> originalObservable = original.toObservable();\n        Observable<Boolean> fromCacheObservable = fromCache.toObservable();\n\n        Subscription originalSubscription = originalObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original Unsubscribe\");\n                originalLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnCompleted\");\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnError : \" + e);\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnNext : \" + b);\n                originalValue.set(b);\n            }\n        });\n\n        Subscription fromCacheSubscription = fromCacheObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache Unsubscribe\");\n                fromCacheLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache OnCompleted\");\n                fromCacheLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache OnError : \" + e);\n                fromCacheLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache OnNext : \" + b);\n                fromCacheValue.set(b);\n            }\n        });\n\n        try {\n            Thread.sleep(10);\n            originalSubscription.unsubscribe();\n            assertTrue(originalLatch.await(600, TimeUnit.MILLISECONDS));\n            assertTrue(fromCacheLatch.await(600, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use (original)\", 0, original.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (original)\", 0, original.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(original.isExecutionComplete());\n            assertTrue(original.isExecutedInThread());\n            assertEquals(null, original.getFailedExecutionException());\n            assertNull(original.getExecutionException());\n            assertTrue(original.getExecutionTimeInMilliseconds() > -1);\n            assertFalse(original.isSuccessfulExecution());\n            assertCommandExecutionEvents(original, HystrixEventType.CANCELLED);\n            assertNull(originalValue.get());\n            assertEquals(0, original.metrics.getCurrentConcurrentExecutionCount());\n\n            assertEquals(\"Number of execution semaphores in use (fromCache)\", 0, fromCache.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache)\", 0, fromCache.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertTrue(fromCache.isExecutionComplete());\n            assertFalse(fromCache.isExecutedInThread());\n            assertEquals(null, fromCache.getFailedExecutionException());\n            assertNull(fromCache.getExecutionException());\n            assertCommandExecutionEvents(fromCache, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n            assertTrue(fromCache.getExecutionTimeInMilliseconds() == -1);\n            assertTrue(fromCache.isSuccessfulExecution());\n            assertEquals(0, fromCache.metrics.getCurrentConcurrentExecutionCount());\n\n            assertFalse(original.isCancelled());  //underlying work\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n            assertSaneHystrixRequestLog(2);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsOriginalAndOneCacheHitUnsubscribed() {\n        AsyncCacheableCommand original = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache1 = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache2 = new AsyncCacheableCommand(\"foo\");\n\n        final AtomicReference<Boolean> originalValue = new AtomicReference<Boolean>(null);\n        final AtomicReference<Boolean> fromCache1Value = new AtomicReference<Boolean>(null);\n        final AtomicReference<Boolean> fromCache2Value = new AtomicReference<Boolean>(null);\n\n        final CountDownLatch originalLatch = new CountDownLatch(1);\n        final CountDownLatch fromCache1Latch = new CountDownLatch(1);\n        final CountDownLatch fromCache2Latch = new CountDownLatch(1);\n\n        Observable<Boolean> originalObservable = original.toObservable();\n        Observable<Boolean> fromCache1Observable = fromCache1.toObservable();\n        Observable<Boolean> fromCache2Observable = fromCache2.toObservable();\n\n        Subscription originalSubscription = originalObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original Unsubscribe\");\n                originalLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnCompleted\");\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnError : \" + e);\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnNext : \" + b);\n                originalValue.set(b);\n            }\n        });\n\n        Subscription fromCache1Subscription = fromCache1Observable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 Unsubscribe\");\n                fromCache1Latch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnCompleted\");\n                fromCache1Latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnError : \" + e);\n                fromCache1Latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnNext : \" + b);\n                fromCache1Value.set(b);\n            }\n        });\n\n        Subscription fromCache2Subscription = fromCache2Observable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 Unsubscribe\");\n                fromCache2Latch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnCompleted\");\n                fromCache2Latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnError : \" + e);\n                fromCache2Latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnNext : \" + b);\n                fromCache2Value.set(b);\n            }\n        });\n\n        try {\n            Thread.sleep(10);\n            originalSubscription.unsubscribe();\n            //fromCache1Subscription.unsubscribe();\n            fromCache2Subscription.unsubscribe();\n            assertTrue(originalLatch.await(600, TimeUnit.MILLISECONDS));\n            assertTrue(fromCache1Latch.await(600, TimeUnit.MILLISECONDS));\n            assertTrue(fromCache2Latch.await(600, TimeUnit.MILLISECONDS));\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n            assertEquals(\"Number of execution semaphores in use (original)\", 0, original.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (original)\", 0, original.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(original.isExecutionComplete());\n            assertTrue(original.isExecutedInThread());\n            assertEquals(null, original.getFailedExecutionException());\n            assertNull(original.getExecutionException());\n            assertTrue(original.getExecutionTimeInMilliseconds() > -1);\n            assertFalse(original.isSuccessfulExecution());\n            assertCommandExecutionEvents(original, HystrixEventType.CANCELLED);\n            assertNull(originalValue.get());\n            assertFalse(original.isCancelled());   //underlying work\n            assertEquals(0, original.metrics.getCurrentConcurrentExecutionCount());\n\n\n            assertEquals(\"Number of execution semaphores in use (fromCache1)\", 0, fromCache1.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache1)\", 0, fromCache1.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertTrue(fromCache1.isExecutionComplete());\n            assertFalse(fromCache1.isExecutedInThread());\n            assertEquals(null, fromCache1.getFailedExecutionException());\n            assertNull(fromCache1.getExecutionException());\n            assertCommandExecutionEvents(fromCache1, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n            assertTrue(fromCache1.getExecutionTimeInMilliseconds() == -1);\n            assertTrue(fromCache1.isSuccessfulExecution());\n            assertTrue(fromCache1Value.get());\n            assertEquals(0, fromCache1.metrics.getCurrentConcurrentExecutionCount());\n\n\n            assertEquals(\"Number of execution semaphores in use (fromCache2)\", 0, fromCache2.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache2)\", 0, fromCache2.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(fromCache2.isExecutionComplete());\n            assertFalse(fromCache2.isExecutedInThread());\n            assertEquals(null, fromCache2.getFailedExecutionException());\n            assertNull(fromCache2.getExecutionException());\n            assertCommandExecutionEvents(fromCache2, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);\n            assertTrue(fromCache2.getExecutionTimeInMilliseconds() == -1);\n            assertFalse(fromCache2.isSuccessfulExecution());\n            assertNull(fromCache2Value.get());\n            assertEquals(0, fromCache2.metrics.getCurrentConcurrentExecutionCount());\n\n            assertSaneHystrixRequestLog(3);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsAllUnsubscribed() {\n        AsyncCacheableCommand original = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache1 = new AsyncCacheableCommand(\"foo\");\n        AsyncCacheableCommand fromCache2 = new AsyncCacheableCommand(\"foo\");\n\n        final CountDownLatch originalLatch = new CountDownLatch(1);\n        final CountDownLatch fromCache1Latch = new CountDownLatch(1);\n        final CountDownLatch fromCache2Latch = new CountDownLatch(1);\n\n        Observable<Boolean> originalObservable = original.toObservable();\n        Observable<Boolean> fromCache1Observable = fromCache1.toObservable();\n        Observable<Boolean> fromCache2Observable = fromCache2.toObservable();\n\n        Subscription originalSubscription = originalObservable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original Unsubscribe\");\n                originalLatch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnCompleted\");\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnError : \" + e);\n                originalLatch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.Original OnNext : \" + b);\n            }\n        });\n\n        Subscription fromCache1Subscription = fromCache1Observable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 Unsubscribe\");\n                fromCache1Latch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnCompleted\");\n                fromCache1Latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnError : \" + e);\n                fromCache1Latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache1 OnNext : \" + b);\n            }\n        });\n\n        Subscription fromCache2Subscription = fromCache2Observable.doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 Unsubscribe\");\n                fromCache2Latch.countDown();\n            }\n        }).subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnCompleted\");\n                fromCache2Latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnError : \" + e);\n                fromCache2Latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Test.FromCache2 OnNext : \" + b);\n            }\n        });\n\n        try {\n            Thread.sleep(10);\n            originalSubscription.unsubscribe();\n            fromCache1Subscription.unsubscribe();\n            fromCache2Subscription.unsubscribe();\n            assertTrue(originalLatch.await(200, TimeUnit.MILLISECONDS));\n            assertTrue(fromCache1Latch.await(200, TimeUnit.MILLISECONDS));\n            assertTrue(fromCache2Latch.await(200, TimeUnit.MILLISECONDS));\n            System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n            assertEquals(\"Number of execution semaphores in use (original)\", 0, original.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (original)\", 0, original.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(original.isExecutionComplete());\n            assertTrue(original.isExecutedInThread());\n            System.out.println(\"FEE : \" + original.getFailedExecutionException());\n            if (original.getFailedExecutionException() != null) {\n                original.getFailedExecutionException().printStackTrace();\n            }\n            assertNull(original.getFailedExecutionException());\n            assertNull(original.getExecutionException());\n            assertTrue(original.getExecutionTimeInMilliseconds() > -1);\n            assertFalse(original.isSuccessfulExecution());\n            assertCommandExecutionEvents(original, HystrixEventType.CANCELLED);\n            //assertTrue(original.isCancelled());   //underlying work  This doesn't work yet\n            assertEquals(0, original.metrics.getCurrentConcurrentExecutionCount());\n\n\n            assertEquals(\"Number of execution semaphores in use (fromCache1)\", 0, fromCache1.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache1)\", 0, fromCache1.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(fromCache1.isExecutionComplete());\n            assertFalse(fromCache1.isExecutedInThread());\n            assertEquals(null, fromCache1.getFailedExecutionException());\n            assertNull(fromCache1.getExecutionException());\n            assertCommandExecutionEvents(fromCache1, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);\n            assertTrue(fromCache1.getExecutionTimeInMilliseconds() == -1);\n            assertFalse(fromCache1.isSuccessfulExecution());\n            assertEquals(0, fromCache1.metrics.getCurrentConcurrentExecutionCount());\n\n\n            assertEquals(\"Number of execution semaphores in use (fromCache2)\", 0, fromCache2.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use (fromCache2)\", 0, fromCache2.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(fromCache2.isExecutionComplete());\n            assertFalse(fromCache2.isExecutedInThread());\n            assertEquals(null, fromCache2.getFailedExecutionException());\n            assertNull(fromCache2.getExecutionException());\n            assertCommandExecutionEvents(fromCache2, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);\n            assertTrue(fromCache2.getExecutionTimeInMilliseconds() == -1);\n            assertFalse(fromCache2.isSuccessfulExecution());\n            assertEquals(0, fromCache2.metrics.getCurrentConcurrentExecutionCount());\n\n            assertSaneHystrixRequestLog(3);\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    /**\n     * Some RxJava operators like take(n), zip receive data in an onNext from upstream and immediately unsubscribe.\n     * When upstream is a HystrixCommand, Hystrix may get that unsubscribe before it gets to its onCompleted.\n     * This should still be marked as a HystrixEventType.SUCCESS.\n     */\n    @Test\n    public void testUnsubscribingDownstreamOperatorStillResultsInSuccessEventType() throws InterruptedException {\n        HystrixCommand<Integer> cmd = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 100, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n\n        Observable<Integer> o = cmd.toObservable()\n                .doOnNext(new Action1<Integer>() {\n                    @Override\n                    public void call(Integer i) {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" CMD OnNext : \" + i);\n                    }\n                })\n                .doOnError(new Action1<Throwable>() {\n                    @Override\n                    public void call(Throwable throwable) {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" CMD OnError : \" + throwable);\n                    }\n                })\n                .doOnCompleted(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" CMD OnCompleted\");\n                    }\n                })\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" CMD OnSubscribe\");\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" CMD OnUnsubscribe\");\n                    }\n                })\n                .take(1)\n                .observeOn(Schedulers.io())\n                .map(new Func1<Integer, Integer>() {\n                    @Override\n                    public Integer call(Integer i) {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : Doing some more computation in the onNext!!\");\n                        try {\n                            Thread.sleep(100);\n                        } catch (InterruptedException ex) {\n                            ex.printStackTrace();\n                        }\n                        return i;\n                    }\n                });\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        o.doOnSubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : OnSubscribe\");\n            }\n        }).doOnUnsubscribe(new Action0() {\n            @Override\n            public void call() {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : OnUnsubscribe\");\n            }\n        }).subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : OnError : \" + e);\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer i) {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" : OnNext : \" + i);\n            }\n        });\n\n        latch.await(1000, TimeUnit.MILLISECONDS);\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(cmd.isExecutedInThread());\n        assertCommandExecutionEvents(cmd, HystrixEventType.SUCCESS);\n    }\n\n    @Test\n    public void testUnsubscribeBeforeSubscribe() throws Exception {\n        //this may happen in Observable chain, so Hystrix should make sure that command never executes/allocates in this situation\n        Observable<String> error = Observable.error(new RuntimeException(\"foo\"));\n        HystrixCommand<Integer> cmd = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 100);\n        Observable<Integer> cmdResult = cmd.toObservable()\n                .doOnNext(new Action1<Integer>() {\n                    @Override\n                    public void call(Integer integer) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + integer);\n                    }\n                })\n                .doOnError(new Action1<Throwable>() {\n                    @Override\n                    public void call(Throwable ex) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + ex);\n                    }\n                })\n                .doOnCompleted(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                    }\n                })\n                .doOnSubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnSubscribe\");\n                    }\n                })\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnUnsubscribe\");\n                    }\n                });\n\n        //the zip operator will subscribe to each observable.  there is a race between the error of the first\n        //zipped observable terminating the zip and the subscription to the command's observable\n        Observable<String> zipped = Observable.zip(error, cmdResult, new Func2<String, Integer, String>() {\n            @Override\n            public String call(String s, Integer integer) {\n                return s + integer;\n            }\n        });\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        zipped.subscribe(new Subscriber<String>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnError : \" + e);\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(String s) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnNext : \" + s);\n            }\n        });\n\n        latch.await(1000, TimeUnit.MILLISECONDS);\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n    }\n\n    @Test\n    public void testRxRetry() throws Exception {\n        // see https://github.com/Netflix/Hystrix/issues/1100\n        // Since each command instance is single-use, the expectation is that applying the .retry() operator\n        // results in only a single execution and propagation out of that error\n        HystrixCommand<Integer> cmd = getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 300,\n                AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        System.out.println(System.currentTimeMillis() + \" : Starting\");\n        Observable<Integer> o = cmd.toObservable().retry(2);\n        System.out.println(System.currentTimeMillis() + \" Created retried command : \" + o);\n\n        o.subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + e);\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer integer) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + integer);\n            }\n        });\n\n        latch.await(1000, TimeUnit.MILLISECONDS);\n        System.out.println(System.currentTimeMillis() + \" ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n    }\n\n    /**\n     *********************** THREAD-ISOLATED Execution Hook Tests **************************************\n     */\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: NO\n     * Execution Result: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadSuccess() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(1, 0, 1));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionSuccess - onThreadComplete - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    @Test\n    public void testExecutionHookEarlyUnsubscribe() {\n        System.out.println(\"Running command.observe(), awaiting terminal state of Observable, then running assertions...\");\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        TestHystrixCommand<Integer> command = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 1000);\n        Observable<Integer> o = command.observe();\n\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Integer>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + e);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(Integer i) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + i);\n                    }\n        });\n\n        try {\n            Thread.sleep(15);\n            s.unsubscribe();\n            latch.await(3, TimeUnit.SECONDS);\n            TestableExecutionHook hook = command.getBuilder().executionHook;\n            assertTrue(hook.commandEmissionsMatch(0, 0, 0));\n            assertTrue(hook.executionEventsMatch(0, 0, 0));\n            assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n            assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onUnsubscribe - onThreadComplete - \", hook.executionSequence.toString());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: NO\n     * Execution Result: synchronous HystrixBadRequestException\n     */\n    @Test\n    public void testExecutionHookThreadBadRequestException() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(HystrixBadRequestException.class, hook.getCommandException().getClass());\n                        assertEquals(HystrixBadRequestException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadExceptionNoFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 0, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadExceptionSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 0, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: NO\n     * Execution Result: synchronous HystrixRuntimeException\n     * Fallback: HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadExceptionUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 0, AbstractTestHystrixCommand.FallbackResult.FAILURE);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: SUCCESS (but timeout prior)\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutNoFallbackRunSuccess() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(TimeoutException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        System.out.println(\"RequestLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: SUCCESS (but timeout prior)\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutSuccessfulFallbackRunSuccess() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        System.out.println(\"RequestLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: SUCCESS (but timeout prior)\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutUnsuccessfulFallbackRunSuccess() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(TimeoutException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: HystrixRuntimeException (but timeout prior)\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutNoFallbackRunFailure() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(TimeoutException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onError - \", hook.executionSequence.toString());\n\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: HystrixRuntimeException (but timeout prior)\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutSuccessfulFallbackRunFailure() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : NO\n     * Thread Pool Queue full?: NO\n     * Timeout: YES\n     * Execution Result: HystrixRuntimeException (but timeout prior)\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadTimeoutUnsuccessfulFallbackRunFailure() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, 200);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(TimeoutException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onThreadComplete - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: YES\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadPoolQueueFullNoFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithQueue(1);\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, circuitBreaker, pool, 600).observe();\n                            // fill the queue\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RejectedExecutionException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: YES\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadPoolQueueFullSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithQueue(1);\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker, pool, 600).observe();\n                            // fill the queue\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(\"onStart - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: YES\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadPoolQueueFullUnsuccessfulFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithQueue(1);\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, circuitBreaker, pool, 600).observe();\n                            // fill the queue\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RejectedExecutionException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: N/A\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadPoolFullNoFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithNoQueue();\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RejectedExecutionException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: N/A\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadPoolFullSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithNoQueue();\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.SUCCESS, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertEquals(\"onStart - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool full? : YES\n     * Thread Pool Queue full?: N/A\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadPoolFullUnsuccessfulFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker();\n                        HystrixThreadPool pool = new SingleThreadedPoolWithNoQueue();\n                        try {\n                            // fill the pool\n                            getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, circuitBreaker, pool, 600).observe();\n                        } catch (Exception e) {\n                            // ignore\n                        }\n\n                        return getLatentCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, circuitBreaker, pool, 600);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RejectedExecutionException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: THREAD\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadShortCircuitNoFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: THREAD\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadShortCircuitSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(\"onStart - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : YES\n     * Thread/semaphore: THREAD\n     * Fallback: synchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadShortCircuitUnsuccessfulFallback() {\n        assertHooksOnFailFast(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker = new HystrixCircuitBreakerTest.TestCircuitBreaker().setForceShortCircuit(true);\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.FAILURE);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuit? : NO\n     * Request-cache? : YES\n     */\n    @Test\n    public void testExecutionHookResponseFromCache() {\n        final HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Hook-Cache\");\n        getCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 0, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, 100, AbstractTestHystrixCommand.CacheEnabled.YES, 42, 10, 10).observe();\n\n        assertHooksOnSuccess(\n                new Func0<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public TestHystrixCommand<Integer> call() {\n                        return getCommand(key, ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 0, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 0, new HystrixCircuitBreakerTest.TestCircuitBreaker(), null, 100, AbstractTestHystrixCommand.CacheEnabled.YES, 42, 10, 10);\n                    }\n                },\n                new Action1<TestHystrixCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 0, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(\"onCacheHit - \", hook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     *********************** END THREAD-ISOLATED Execution Hook Tests **************************************\n     */\n\n\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n    /* private HystrixCommand class implementations for unit testing */\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n\n    static AtomicInteger uniqueNameCounter = new AtomicInteger(1);\n\n    @Override\n    TestHystrixCommand<Integer> getCommand(ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"Flexible-\" + uniqueNameCounter.getAndIncrement());\n        return FlexibleTestHystrixCommand.from(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    @Override\n    TestHystrixCommand<Integer> getCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n        return FlexibleTestHystrixCommand.from(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    private static class FlexibleTestHystrixCommand {\n\n        public static Integer EXECUTE_VALUE = 1;\n        public static Integer FALLBACK_VALUE = 11;\n\n        public static AbstractFlexibleTestHystrixCommand from(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            if (fallbackResult.equals(AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED)) {\n                return new FlexibleTestHystrixCommandNoFallback(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            } else {\n                return new FlexibleTestHystrixCommandWithFallback(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            }\n        }\n    }\n\n    private static class AbstractFlexibleTestHystrixCommand extends TestHystrixCommand<Integer> {\n        protected final AbstractTestHystrixCommand.ExecutionResult executionResult;\n        protected final int executionLatency;\n\n        protected final CacheEnabled cacheEnabled;\n        protected final Object value;\n\n\n        AbstractFlexibleTestHystrixCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(testPropsBuilder(circuitBreaker)\n                    .setCommandKey(commandKey)\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setThreadPool(threadPool)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(isolationStrategy)\n                            .withExecutionTimeoutInMilliseconds(timeout)\n                            .withCircuitBreakerEnabled(!circuitBreakerDisabled))\n                    .setExecutionSemaphore(executionSemaphore)\n                    .setFallbackSemaphore(fallbackSemaphore));\n            this.executionResult = executionResult;\n            this.executionLatency = executionLatency;\n\n            this.cacheEnabled = cacheEnabled;\n            this.value = value;\n        }\n\n        @Override\n        protected Integer run() throws Exception {\n            System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" starting the run() method\");\n            addLatency(executionLatency);\n            if (executionResult == AbstractTestHystrixCommand.ExecutionResult.SUCCESS) {\n                return FlexibleTestHystrixCommand.EXECUTE_VALUE;\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.FAILURE) {\n                throw new RuntimeException(\"Execution Failure for TestHystrixCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.NOT_WRAPPED_FAILURE) {\n                throw new NotWrappedByHystrixTestRuntimeException();\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.HYSTRIX_FAILURE) {\n                throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION, AbstractFlexibleTestHystrixCommand.class, \"Execution Hystrix Failure for TestHystrixCommand\", new RuntimeException(\"Execution Failure for TestHystrixCommand\"), new RuntimeException(\"Fallback Failure for TestHystrixCommand\"));\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.RECOVERABLE_ERROR) {\n                throw new java.lang.Error(\"Execution ERROR for TestHystrixCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.UNRECOVERABLE_ERROR) {\n                throw new StackOverflowError(\"Unrecoverable Error for TestHystrixCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST) {\n                throw new HystrixBadRequestException(\"Execution BadRequestException for TestHystrixCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST_NOT_WRAPPED) {\n                throw new HystrixBadRequestException(\"Execution BadRequestException for TestHystrixCommand\", new NotWrappedByHystrixTestRuntimeException());\n            } else {\n                throw new RuntimeException(\"You passed in a executionResult enum that can't be represented in HystrixCommand: \" + executionResult);\n            }\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled == CacheEnabled.YES)\n                return value.toString();\n            else\n                return null;\n        }\n\n        protected void addLatency(int latency) {\n            if (latency > 0) {\n                try {\n                    System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" About to sleep for : \" + latency);\n                    Thread.sleep(latency);\n                    System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Woke up from sleep!\");\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                    // ignore and sleep some more to simulate a dependency that doesn't obey interrupts\n                    try {\n                        Thread.sleep(latency);\n                    } catch (Exception e2) {\n                        // ignore\n                    }\n                    System.out.println(\"after interruption with extra sleep\");\n                }\n            }\n        }\n\n    }\n\n    private static class FlexibleTestHystrixCommandWithFallback extends AbstractFlexibleTestHystrixCommand {\n        protected final AbstractTestHystrixCommand.FallbackResult fallbackResult;\n        protected final int fallbackLatency;\n\n        FlexibleTestHystrixCommandWithFallback(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            this.fallbackResult = fallbackResult;\n            this.fallbackLatency = fallbackLatency;\n        }\n\n        @Override\n        protected Integer getFallback() {\n            addLatency(fallbackLatency);\n            if (fallbackResult == AbstractTestHystrixCommand.FallbackResult.SUCCESS) {\n                return FlexibleTestHystrixCommand.FALLBACK_VALUE;\n            } else if (fallbackResult == AbstractTestHystrixCommand.FallbackResult.FAILURE) {\n                throw new RuntimeException(\"Fallback Failure for TestHystrixCommand\");\n            } else if (fallbackResult == FallbackResult.UNIMPLEMENTED) {\n                return super.getFallback();\n            } else {\n                throw new RuntimeException(\"You passed in a fallbackResult enum that can't be represented in HystrixCommand: \" + fallbackResult);\n            }\n        }\n    }\n\n    private static class FlexibleTestHystrixCommandNoFallback extends AbstractFlexibleTestHystrixCommand {\n        FlexibleTestHystrixCommandNoFallback(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n        }\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class SuccessfulTestCommand extends TestHystrixCommand<Boolean> {\n\n        public SuccessfulTestCommand() {\n            this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter());\n        }\n\n        public SuccessfulTestCommand(HystrixCommandProperties.Setter properties) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(properties));\n        }\n\n        @Override\n        protected Boolean run() {\n            return true;\n        }\n\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class DynamicOwnerTestCommand extends TestHystrixCommand<Boolean> {\n\n        public DynamicOwnerTestCommand(HystrixCommandGroupKey owner) {\n            super(testPropsBuilder().setOwner(owner));\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\"successfully executed\");\n            return true;\n        }\n\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class DynamicOwnerAndKeyTestCommand extends TestHystrixCommand<Boolean> {\n\n        public DynamicOwnerAndKeyTestCommand(HystrixCommandGroupKey owner, HystrixCommandKey key) {\n            super(testPropsBuilder().setOwner(owner).setCommandKey(key).setCircuitBreaker(null).setMetrics(null));\n            // we specifically are NOT passing in a circuit breaker here so we test that it creates a new one correctly based on the dynamic key\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\"successfully executed\");\n            return true;\n        }\n\n    }\n\n    /**\n     * Failed execution with known exception (HystrixException) - no fallback implementation.\n     */\n    private static class KnownFailureTestCommandWithoutFallback extends TestHystrixCommand<Boolean> {\n\n        private KnownFailureTestCommandWithoutFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\"*** simulated failed execution *** ==> \" + Thread.currentThread());\n            throw new RuntimeException(\"we failed with a simulated issue\");\n        }\n\n    }\n\n    /**\n     * Failed execution - fallback implementation successfully returns value.\n     */\n    private static class KnownFailureTestCommandWithFallback extends TestHystrixCommand<Boolean> {\n\n        public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n        }\n\n        public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker, boolean fallbackEnabled) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withFallbackEnabled(fallbackEnabled)));\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\"*** simulated failed execution ***\");\n            throw new RuntimeException(\"we failed with a simulated issue\");\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCommand<T> extends TestHystrixCommand<T> {\n\n        private final boolean cacheEnabled;\n        private volatile boolean executed = false;\n        private final T value;\n\n        public SuccessfulCacheableCommand(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, T value) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.value = value;\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        protected T run() {\n            executed = true;\n            System.out.println(\"successfully executed\");\n            return value;\n        }\n\n        public boolean isCommandRunningInThread() {\n            return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD);\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return value.toString();\n            else\n                return null;\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCommandViaSemaphore extends TestHystrixCommand<String> {\n\n        private final boolean cacheEnabled;\n        private volatile boolean executed = false;\n        private final String value;\n\n        public SuccessfulCacheableCommandViaSemaphore(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, String value) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));\n            this.value = value;\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        protected String run() {\n            executed = true;\n            System.out.println(\"successfully executed\");\n            return value;\n        }\n\n        public boolean isCommandRunningInThread() {\n            return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD);\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return value;\n            else\n                return null;\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching and execution takes a while.\n     * <p>\n     * Used to test scenario where Futures are returned with a backing call still executing.\n     */\n    private static class SlowCacheableCommand extends TestHystrixCommand<String> {\n\n        private final String value;\n        private final int duration;\n        private volatile boolean executed = false;\n\n        public SlowCacheableCommand(TestCircuitBreaker circuitBreaker, String value, int duration) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.value = value;\n            this.duration = duration;\n        }\n\n        @Override\n        protected String run() {\n            executed = true;\n            try {\n                Thread.sleep(duration);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            System.out.println(\"successfully executed\");\n            return value;\n        }\n\n        @Override\n        public String getCacheKey() {\n            return value;\n        }\n    }\n\n    /**\n     * This has a ThreadPool that has a single thread and queueSize of 1.\n     */\n    private static class TestCommandRejection extends TestHystrixCommand<Boolean> {\n\n        private final static int FALLBACK_NOT_IMPLEMENTED = 1;\n        private final static int FALLBACK_SUCCESS = 2;\n        private final static int FALLBACK_FAILURE = 3;\n\n        private final int fallbackBehavior;\n\n        private final int sleepTime;\n\n        private TestCommandRejection(HystrixCommandKey key, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int sleepTime, int timeout, int fallbackBehavior) {\n            super(testPropsBuilder()\n                    .setCommandKey(key)\n                    .setThreadPool(threadPool)\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(timeout)));\n            this.fallbackBehavior = fallbackBehavior;\n            this.sleepTime = sleepTime;\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\">>> TestCommandRejection running\");\n            try {\n                Thread.sleep(sleepTime);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return true;\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            if (fallbackBehavior == FALLBACK_SUCCESS) {\n                return false;\n            } else if (fallbackBehavior == FALLBACK_FAILURE) {\n                throw new RuntimeException(\"failed on fallback\");\n            } else {\n                // FALLBACK_NOT_IMPLEMENTED\n                return super.getFallback();\n            }\n        }\n    }\n\n    /**\n     * Command that receives a custom thread-pool, sleepTime, timeout\n     */\n    private static class CommandWithCustomThreadPool extends TestHystrixCommand<Boolean> {\n\n        public boolean didExecute = false;\n\n        private final int sleepTime;\n\n        private CommandWithCustomThreadPool(TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int sleepTime, HystrixCommandProperties.Setter properties) {\n            super(testPropsBuilder().setThreadPool(threadPool).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics).setCommandPropertiesDefaults(properties));\n            this.sleepTime = sleepTime;\n        }\n\n        @Override\n        protected Boolean run() {\n            System.out.println(\"**** Executing CommandWithCustomThreadPool. Execution => \" + sleepTime);\n            didExecute = true;\n            try {\n                Thread.sleep(sleepTime);\n                System.out.println(\"Woke up\");\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return true;\n        }\n    }\n\n    /**\n     * The run() will fail and getFallback() take a long time.\n     */\n    private static class TestSemaphoreCommandWithSlowFallback extends TestHystrixCommand<Boolean> {\n\n        private final long fallbackSleep;\n\n        private TestSemaphoreCommandWithSlowFallback(TestCircuitBreaker circuitBreaker, int fallbackSemaphoreExecutionCount, long fallbackSleep) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withFallbackIsolationSemaphoreMaxConcurrentRequests(fallbackSemaphoreExecutionCount).withExecutionIsolationThreadInterruptOnTimeout(false)));\n            this.fallbackSleep = fallbackSleep;\n        }\n\n        @Override\n        protected Boolean run() {\n            throw new RuntimeException(\"run fails\");\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            try {\n                Thread.sleep(fallbackSleep);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return true;\n        }\n    }\n\n    private static class NoRequestCacheTimeoutWithoutFallback extends TestHystrixCommand<Boolean> {\n        public NoRequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(200).withCircuitBreakerEnabled(false)));\n\n            // we want it to timeout\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                System.out.println(\">>>> Sleep Interrupted: \" + e.getMessage());\n                //                    e.printStackTrace();\n            }\n            return true;\n        }\n\n        @Override\n        public String getCacheKey() {\n            return null;\n        }\n    }\n\n    /**\n     * The run() will take time. Configurable fallback implementation.\n     */\n    private static class TestSemaphoreCommand extends TestHystrixCommand<Boolean> {\n\n        private final long executionSleep;\n\n        private final static int RESULT_SUCCESS = 1;\n        private final static int RESULT_FAILURE = 2;\n        private final static int RESULT_BAD_REQUEST_EXCEPTION = 3;\n\n        private final int resultBehavior;\n\n        private final static int FALLBACK_SUCCESS = 10;\n        private final static int FALLBACK_NOT_IMPLEMENTED = 11;\n        private final static int FALLBACK_FAILURE = 12;\n\n        private final int fallbackBehavior;\n\n        private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep, int resultBehavior, int fallbackBehavior) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)\n                            .withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount)));\n            this.executionSleep = executionSleep;\n            this.resultBehavior = resultBehavior;\n            this.fallbackBehavior = fallbackBehavior;\n        }\n\n        private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphore semaphore, long executionSleep, int resultBehavior, int fallbackBehavior) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))\n                    .setExecutionSemaphore(semaphore));\n            this.executionSleep = executionSleep;\n            this.resultBehavior = resultBehavior;\n            this.fallbackBehavior = fallbackBehavior;\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(executionSleep);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            if (resultBehavior == RESULT_SUCCESS) {\n                return true;\n            } else if (resultBehavior == RESULT_FAILURE) {\n                throw new RuntimeException(\"TestSemaphoreCommand failure\");\n            } else if (resultBehavior == RESULT_BAD_REQUEST_EXCEPTION) {\n                throw new HystrixBadRequestException(\"TestSemaphoreCommand BadRequestException\");\n            } else {\n                throw new IllegalStateException(\"Didn't use a proper enum for result behavior\");\n            }\n        }\n\n\n        @Override\n        protected Boolean getFallback() {\n            if (fallbackBehavior == FALLBACK_SUCCESS) {\n                return false;\n            } else if (fallbackBehavior == FALLBACK_FAILURE) {\n                throw new RuntimeException(\"fallback failure\");\n            } else { //FALLBACK_NOT_IMPLEMENTED\n                return super.getFallback();\n            }\n        }\n    }\n\n    /**\n     * Semaphore based command that allows caller to use latches to know when it has started and signal when it\n     * would like the command to finish\n     */\n    private static class LatchedSemaphoreCommand extends TestHystrixCommand<Boolean> {\n\n        private final CountDownLatch startLatch, waitLatch;\n\n        /**\n         *\n         * @param circuitBreaker circuit breaker (passed in so it may be shared)\n         * @param semaphore semaphore (passed in so it may be shared)\n         * @param startLatch\n         *            this command calls {@link java.util.concurrent.CountDownLatch#countDown()} immediately\n         *            upon running\n         * @param waitLatch\n         *            this command calls {@link java.util.concurrent.CountDownLatch#await()} once it starts\n         *            to run. The caller can use the latch to signal the command to finish\n         */\n        private LatchedSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphore semaphore, CountDownLatch startLatch, CountDownLatch waitLatch) {\n            this(\"Latched\", circuitBreaker, semaphore, startLatch, waitLatch);\n        }\n\n        private LatchedSemaphoreCommand(String commandName, TestCircuitBreaker circuitBreaker, TryableSemaphore semaphore,\n                                        CountDownLatch startLatch, CountDownLatch waitLatch) {\n            super(testPropsBuilder()\n                    .setCommandKey(HystrixCommandKey.Factory.asKey(commandName))\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)\n                            .withCircuitBreakerEnabled(false))\n                    .setExecutionSemaphore(semaphore));\n            this.startLatch = startLatch;\n            this.waitLatch = waitLatch;\n        }\n\n        @Override\n        protected Boolean run() {\n            // signals caller that run has started\n            this.startLatch.countDown();\n\n            try {\n                // waits for caller to countDown latch\n                this.waitLatch.await();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n                return false;\n            }\n            return true;\n        }\n    }\n\n    /**\n     * The run() will take time. Contains fallback.\n     */\n    private static class TestSemaphoreCommandWithFallback extends TestHystrixCommand<Boolean> {\n\n        private final long executionSleep;\n        private final Boolean fallback;\n\n        private TestSemaphoreCommandWithFallback(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep, Boolean fallback) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount)));\n            this.executionSleep = executionSleep;\n            this.fallback = fallback;\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(executionSleep);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return true;\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return fallback;\n        }\n\n    }\n\n    private static class RequestCacheNullPointerExceptionCase extends TestHystrixCommand<Boolean> {\n        public RequestCacheNullPointerExceptionCase(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(200)));\n            // we want it to timeout\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return true;\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class RequestCacheTimeoutWithoutFallback extends TestHystrixCommand<Boolean> {\n        public RequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(200).withCircuitBreakerEnabled(false)));\n            // we want it to timeout\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                System.out.println(\">>>> Sleep Interrupted: \" + e.getMessage());\n                //                    e.printStackTrace();\n            }\n            return true;\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class RequestCacheThreadRejectionWithoutFallback extends TestHystrixCommand<Boolean> {\n\n        final CountDownLatch completionLatch;\n\n        public RequestCacheThreadRejectionWithoutFallback(TestCircuitBreaker circuitBreaker, CountDownLatch completionLatch) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setThreadPool(new HystrixThreadPool() {\n\n                        @Override\n                        public ThreadPoolExecutor getExecutor() {\n                            return null;\n                        }\n\n                        @Override\n                        public void markThreadExecution() {\n\n                        }\n\n                        @Override\n                        public void markThreadCompletion() {\n\n                        }\n\n                        @Override\n                        public void markThreadRejection() {\n\n                        }\n\n                        @Override\n                        public boolean isQueueSpaceAvailable() {\n                            // always return false so we reject everything\n                            return false;\n                        }\n\n                        @Override\n                        public Scheduler getScheduler() {\n                            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);\n                        }\n\n                        @Override\n                        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n                            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n                        }\n\n                    }));\n            this.completionLatch = completionLatch;\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                if (completionLatch.await(1000, TimeUnit.MILLISECONDS)) {\n                    throw new RuntimeException(\"timed out waiting on completionLatch\");\n                }\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n            return true;\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class BadRequestCommand extends TestHystrixCommand<Boolean> {\n\n        public BadRequestCommand(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationType) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationType))\n                    .setMetrics(circuitBreaker.metrics));\n        }\n\n        @Override\n        protected Boolean run() {\n            throw new HystrixBadRequestException(\"Message to developer that they passed in bad data or something like that.\");\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return \"one\";\n        }\n\n    }\n\n    private static class AsyncCacheableCommand extends HystrixCommand<Boolean> {\n        private final String arg;\n        private final AtomicBoolean cancelled = new AtomicBoolean(false);\n\n        public AsyncCacheableCommand(String arg) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            this.arg = arg;\n        }\n\n        @Override\n        protected Boolean run() {\n            try {\n                Thread.sleep(500);\n                return true;\n            } catch (InterruptedException ex) {\n                cancelled.set(true);\n                throw new RuntimeException(ex);\n            }\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return arg;\n        }\n\n        public boolean isCancelled() {\n            return cancelled.get();\n        }\n    }\n\n    private static class BusinessException extends Exception {\n        public BusinessException(String msg) {\n            super(msg);\n        }\n    }\n\n    private static class ExceptionToBadRequestByExecutionHookCommand extends TestHystrixCommand<Boolean> {\n        public ExceptionToBadRequestByExecutionHookCommand(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationType) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationType))\n                    .setMetrics(circuitBreaker.metrics)\n                    .setExecutionHook(new TestableExecutionHook(){\n                        @Override\n                        public <T> Exception onRunError(HystrixInvokable<T> commandInstance, Exception e) {\n                            super.onRunError(commandInstance, e);\n                            return new HystrixBadRequestException(\"autoconverted exception\", e);\n                        }\n                    }));\n        }\n\n        @Override\n        protected Boolean run() throws BusinessException {\n            throw new BusinessException(\"invalid input by the user\");\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return \"nein\";\n        }\n    }\n\n    private static class CommandWithCheckedException extends TestHystrixCommand<Boolean> {\n\n        public CommandWithCheckedException(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            throw new IOException(\"simulated checked exception message\");\n        }\n\n    }\n\n    private static class CommandWithNotWrappedByHystrixException extends TestHystrixCommand<Boolean> {\n\n        public CommandWithNotWrappedByHystrixException(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            throw new NotWrappedByHystrixTestException();\n        }\n\n    }\n\n    private static class InterruptibleCommand extends TestHystrixCommand<Boolean> {\n\n        public InterruptibleCommand(TestCircuitBreaker circuitBreaker, boolean shouldInterrupt, boolean shouldInterruptOnCancel, int timeoutInMillis) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                    \t\t.withExecutionIsolationThreadInterruptOnFutureCancel(shouldInterruptOnCancel)\n                            .withExecutionIsolationThreadInterruptOnTimeout(shouldInterrupt)\n                            .withExecutionTimeoutInMilliseconds(timeoutInMillis)));\n        }\n\n        public InterruptibleCommand(TestCircuitBreaker circuitBreaker, boolean shouldInterrupt) {\n        \tthis(circuitBreaker, shouldInterrupt, false, 100);\n        }\n\n        private volatile boolean hasBeenInterrupted;\n\n        public boolean hasBeenInterrupted() {\n            return hasBeenInterrupted;\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            try {\n                Thread.sleep(2000);\n            }\n            catch (InterruptedException e) {\n                System.out.println(\"Interrupted!\");\n                e.printStackTrace();\n                hasBeenInterrupted = true;\n            }\n\n            return hasBeenInterrupted;\n        }\n    }\n\n    private static class CommandWithDisabledTimeout extends TestHystrixCommand<Boolean> {\n        private final int latency;\n\n        public CommandWithDisabledTimeout(int timeout, int latency) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                    .withExecutionTimeoutInMilliseconds(timeout)\n                    .withExecutionTimeoutEnabled(false)));\n            this.latency = latency;\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            try {\n                Thread.sleep(latency);\n                return true;\n            } catch (InterruptedException ex) {\n                return false;\n            }\n        }\n\n        @Override\n        protected Boolean getFallback() {\n            return false;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTestWithCustomConcurrencyStrategy.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.concurrent.Callable;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixCommandTestWithCustomConcurrencyStrategy {\n\n    @Before\n    public void init() {\n        HystrixPlugins.reset();\n    }\n\n    @After\n    public void reset() {\n        HystrixRequestContext.setContextOnCurrentThread(null);\n        HystrixPropertiesFactory.reset();\n        HystrixPlugins.reset();\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : true\n     * HystrixCommand\n     ** useRequestCache   : true\n     ** useRequestLog     : true\n     *\n     * OUTCOME: RequestLog set up properly in command\n     */\n    @Test\n    public void testCommandRequiresContextConcurrencyStrategyProvidesItContextSetUpCorrectly() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(true);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is set up properly\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute());\n        printRequestLog();\n        assertNotNull(HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertNotNull(cmd.currentRequestLog);\n        context.shutdown();\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : true\n     * HystrixCommand\n     ** useRequestCache   : true\n     ** useRequestLog     : true\n     *\n     * OUTCOME: RequestLog not set up properly in command, static access is null\n     */\n    @Test\n    public void testCommandRequiresContextConcurrencyStrategyProvidesItContextLeftUninitialized() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(true);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is not set up\n        HystrixRequestContext.setContextOnCurrentThread(null);\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute()); //command execution not affected by missing context\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : false\n     * HystrixCommand\n     ** useRequestCache   : true\n     ** useRequestLog     : true\n     *\n     * OUTCOME: RequestLog not set up in command, not available statically\n     */\n    @Test\n    public void testCommandRequiresContextConcurrencyStrategyDoesNotProvideItContextSetUpCorrectly() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(false);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is set up properly\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute());\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n        context.shutdown();\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : false\n     * HystrixCommand\n     ** useRequestCache   : true\n     ** useRequestLog     : true\n     *\n     * OUTCOME: RequestLog not set up in command, not available statically\n     */\n    @Test\n    public void testCommandRequiresContextConcurrencyStrategyDoesNotProvideItContextLeftUninitialized() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(false);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is not set up\n        HystrixRequestContext.setContextOnCurrentThread(null);\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute()); //command execution not affected by missing context\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : true\n     * HystrixCommand\n     ** useRequestCache   : false\n     ** useRequestLog     : false\n     *\n     * OUTCOME: RequestLog not set up in command, static access works properly\n     */\n    @Test\n    public void testCommandDoesNotRequireContextConcurrencyStrategyProvidesItContextSetUpCorrectly() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(true);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is set up properly\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        HystrixCommand<Boolean> cmd = new TestCommand(false, false);\n        assertTrue(cmd.execute());\n        printRequestLog();\n        assertNotNull(HystrixRequestLog.getCurrentRequest());\n        assertNotNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n        context.shutdown();\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : true\n     * HystrixCommand\n     ** useRequestCache   : false\n     ** useRequestLog     : false\n     *\n     * OUTCOME: RequestLog not set up in command, static access is null\n     */\n    @Test\n    public void testCommandDoesNotRequireContextConcurrencyStrategyProvidesItContextLeftUninitialized() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(true);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is not set up\n        HystrixRequestContext.setContextOnCurrentThread(null);\n        HystrixCommand<Boolean> cmd = new TestCommand(false, false);\n        assertTrue(cmd.execute()); //command execution not affected by missing context\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n    }\n\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : false\n     * HystrixCommand\n     ** useRequestCache   : false\n     ** useRequestLog     : false\n     *\n     * OUTCOME: RequestLog not set up in command, not available statically\n     */\n    @Test\n    public void testCommandDoesNotRequireContextConcurrencyStrategyDoesNotProvideItContextSetUpCorrectly() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(false);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is set up properly\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute());\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n        context.shutdown();\n    }\n\n    /**\n     * HystrixConcurrencyStrategy\n     ** useDefaultRequestContext : false\n     * HystrixCommand\n     ** useRequestCache   : false\n     ** useRequestLog     : false\n     *\n     * OUTCOME: RequestLog not set up in command, not available statically\n     */\n    @Test\n    public void testCommandDoesNotRequireContextConcurrencyStrategyDoesNotProvideItContextLeftUninitialized() {\n        HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(false);\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);\n\n        //context is not set up\n        HystrixRequestContext.setContextOnCurrentThread(null);\n        HystrixCommand<Boolean> cmd = new TestCommand(true, true);\n        assertTrue(cmd.execute()); //command execution unaffected by missing context\n        printRequestLog();\n        assertNull(HystrixRequestLog.getCurrentRequest());\n        assertNull(HystrixRequestLog.getCurrentRequest(strategy));\n        assertNull(cmd.currentRequestLog);\n    }\n\n\n    public static class TestCommand extends HystrixCommand<Boolean> {\n\n        public TestCommand(boolean cacheEnabled, boolean logEnabled) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TEST\")).andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withRequestCacheEnabled(cacheEnabled).withRequestLogEnabled(logEnabled)));\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            return true;\n        }\n    }\n\n    private static void printRequestLog() {\n        HystrixRequestLog currentLog = HystrixRequestLog.getCurrentRequest();\n        if (currentLog != null) {\n            System.out.println(\"RequestLog contents : \" + currentLog.getExecutedCommandsAsString());\n        } else {\n            System.out.println(\"<NULL> HystrixRequestLog\");\n        }\n    }\n\n    public static class CustomConcurrencyStrategy extends HystrixConcurrencyStrategy {\n        private final boolean useDefaultRequestContext;\n\n        public CustomConcurrencyStrategy(boolean useDefaultRequestContext) {\n            this.useDefaultRequestContext = useDefaultRequestContext;\n        }\n\n        @Override\n        public <T> Callable<T> wrapCallable(Callable<T> callable) {\n            return new LoggingCallable<T>(callable);\n        }\n\n        @Override\n        public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {\n            if (useDefaultRequestContext) {\n                //this is the default RequestVariable implementation that requires a HystrixRequestContext\n                return super.getRequestVariable(rv);\n            } else {\n                //this ignores the HystrixRequestContext\n                return new HystrixRequestVariableDefault<T>() {\n                    @Override\n                    public T initialValue() {\n                        return null;\n                    }\n\n                    @Override\n                    public T get() {\n                        return null;\n                    }\n\n                    @Override\n                    public void set(T value) {\n                        //do nothing\n                    }\n\n                    @Override\n                    public void remove() {\n                        //do nothing\n                    }\n\n                    @Override\n                    public void shutdown(T value) {\n                        //do nothing\n                    }\n                };\n            }\n        }\n    }\n\n    public static class LoggingCallable<T> implements Callable<T> {\n\n        private final Callable<T> callable;\n\n        public LoggingCallable(Callable<T> callable) {\n            this.callable = callable;\n        }\n\n        @Override\n        public T call() throws Exception {\n            System.out.println(\"********start call()\");\n            return callable.call();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTimeoutConcurrencyTesting.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport rx.Observable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HystrixCommandTimeoutConcurrencyTesting {\n\n    private final static int NUM_CONCURRENT_COMMANDS = 30;\n\n    @Test\n    public void testTimeoutRace() throws InterruptedException {\n        final int NUM_TRIALS = 10;\n\n        for (int i = 0; i < NUM_TRIALS; i++) {\n            List<Observable<String>> observables = new ArrayList<Observable<String>>();\n            HystrixRequestContext context = null;\n\n            try {\n                context = HystrixRequestContext.initializeContext();\n                for (int j = 0; j < NUM_CONCURRENT_COMMANDS; j++) {\n                    observables.add(new TestCommand().observe());\n                }\n\n                Observable<String> overall = Observable.merge(observables);\n\n                List<String> results = overall.toList().toBlocking().first(); //wait for all commands to complete\n\n                for (String s : results) {\n                    if (s == null) {\n                        System.err.println(\"Received NULL!\");\n                        throw new RuntimeException(\"Received NULL\");\n                    }\n                }\n\n                for (HystrixInvokableInfo<?> hi : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) {\n                    if (!hi.isResponseTimedOut()) {\n                        System.err.println(\"Timeout not found in executed command\");\n                        throw new RuntimeException(\"Timeout not found in executed command\");\n                    }\n                    if (hi.isResponseTimedOut() && hi.getExecutionEvents().size() == 1) {\n                        System.err.println(\"Missing fallback status!\");\n                        throw new RuntimeException(\"Missing fallback status on timeout.\");\n                    }\n                }\n\n            } catch (Exception e) {\n                System.err.println(\"Error: \" + e.getMessage());\n                e.printStackTrace();\n                throw new RuntimeException(e);\n            } finally {\n                System.out.println(HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                if (context != null) {\n                    context.shutdown();\n                }\n            }\n\n            System.out.println(\"*************** TRIAL \" + i + \" ******************\");\n            System.out.println();\n            Thread.sleep(50);\n        }\n\n        Hystrix.reset();\n    }\n\n    public static class TestCommand extends HystrixCommand<String> {\n\n        protected TestCommand() {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"testTimeoutConcurrency\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(\"testTimeoutConcurrencyCommand\"))\n                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                            .withExecutionTimeoutInMilliseconds(3)\n                            .withCircuitBreakerEnabled(false)\n                            .withFallbackIsolationSemaphoreMaxConcurrentRequests(NUM_CONCURRENT_COMMANDS))\n                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()\n                            .withCoreSize(NUM_CONCURRENT_COMMANDS)\n                            .withMaxQueueSize(NUM_CONCURRENT_COMMANDS)\n                            .withQueueSizeRejectionThreshold(NUM_CONCURRENT_COMMANDS)));\n        }\n\n        @Override\n        protected String run() throws Exception {\n            //System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" sleeping\");\n            Thread.sleep(500);\n            //System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" awake and returning\");\n            return \"hello\";\n        }\n\n        @Override\n        protected String getFallback() {\n            return \"failed\";\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCollapserTest.java",
    "content": "/**\n * Copyright 2014 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.netflix.hystrix.collapser.CollapserTimer;\nimport com.netflix.hystrix.collapser.RealCollapserTimer;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesCollapserDefault;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport rx.Observable;\nimport rx.Observable.OnSubscribe;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\nimport rx.observers.TestSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.HystrixCollapserTest.TestCollapserTimer;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixObservableCollapserTest {\n    private static Action1<CollapsedRequest<String, String>> onMissingError = new Action1<CollapsedRequest<String, String>>() {\n        @Override\n        public void call(CollapsedRequest<String, String> collapsedReq) {\n            collapsedReq.setException(new IllegalStateException(\"must have a value\"));\n        }\n    };\n\n     private static Action1<CollapsedRequest<String, String>> onMissingThrow = new Action1<CollapsedRequest<String, String>>() {\n         @Override\n         public void call(CollapsedRequest<String, String> collapsedReq) {\n            throw new RuntimeException(\"synchronous error in onMissingResponse handler\");\n         }\n     };\n\n    private static Action1<CollapsedRequest<String, String>> onMissingComplete = new Action1<CollapsedRequest<String, String>>() {\n        @Override\n        public void call(CollapsedRequest<String, String> collapsedReq) {\n            collapsedReq.setComplete();\n        }\n    };\n\n    private static Action1<CollapsedRequest<String, String>> onMissingIgnore = new Action1<CollapsedRequest<String, String>>() {\n        @Override\n        public void call(CollapsedRequest<String, String> collapsedReq) {\n            //do nothing\n        }\n    };\n\n    private static Action1<CollapsedRequest<String, String>> onMissingFillIn = new Action1<CollapsedRequest<String, String>>() {\n        @Override\n        public void call(CollapsedRequest<String, String> collapsedReq) {\n            collapsedReq.setResponse(\"fillin\");\n        }\n    };\n\n    private static Func1<String, String> prefixMapper = new Func1<String, String>() {\n\n        @Override\n        public String call(String s) {\n            return s.substring(0, s.indexOf(\":\"));\n        }\n\n    };\n\n    private static Func1<String, String> map1To3And2To2 = new Func1<String, String>() {\n        @Override\n        public String call(String s) {\n            String prefix = s.substring(0, s.indexOf(\":\"));\n            if (prefix.equals(\"2\")) {\n                return \"2\";\n            } else {\n                return \"3\";\n            }\n        }\n    };\n\n    private static Func1<String, String> mapWithErrorOn1 = new Func1<String, String>() {\n        @Override\n        public String call(String s) {\n            String prefix = s.substring(0, s.indexOf(\":\"));\n            if (prefix.equals(\"1\")) {\n                throw new RuntimeException(\"poorly implemented demultiplexer\");\n            } else {\n                return \"2\";\n            }\n        }\n    };\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n    private static ExecutorService threadPool = new ThreadPoolExecutor(100, 100, 10, TimeUnit.MINUTES, new SynchronousQueue<Runnable>());\n\n    @Before\n    public void init() {\n        // since we're going to modify properties of the same class between tests, wipe the cache each time\n        HystrixCollapser.reset();\n    }\n\n    @Test\n    public void testTwoRequests() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Future<String> response1 = collapser1.observe().toBlocking().toFuture();\n        Future<String> response2 = collapser2.observe().toBlocking().toFuture();\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertEquals(\"1\", response1.get());\n        assertEquals(\"2\", response2.get());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        Iterator<HystrixInvokableInfo<?>> cmdIterator = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator();\n        assertEquals(2, cmdIterator.next().getNumberCollapsed());\n    }\n\n    @Test\n    public void stressTestRequestCollapser() throws Exception {\n        for(int i = 0; i < 10; i++) {\n            init();\n            testTwoRequests();\n            ctx.reset();\n        }\n    }\n\n    @Test\n    public void testTwoRequestsWhichShouldEachEmitTwice() throws Exception {\n        //TestCollapserTimer timer = new TestCollapserTimer();\n        CollapserTimer timer = new RealCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 3, false, false, prefixMapper, onMissingComplete);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 3, false, false, prefixMapper, onMissingComplete);\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n\n        System.out.println(System.currentTimeMillis() + \"Starting to observe collapser1\");\n        collapser1.observe().subscribe(testSubscriber1);\n        collapser2.observe().subscribe(testSubscriber2);\n        System.out.println(System.currentTimeMillis() + \"Done with collapser observe()s\");\n\n        //Note that removing these awaits breaks the unit test.  That implies that the above subscribe does not wait for a terminal event\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertValues(\"1:1\", \"1:2\", \"1:3\");\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\");\n    }\n\n    @Test\n    public void testTwoRequestsWithErrorProducingBatchCommand() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 3, true);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 3, true);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertError(RuntimeException.class);\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testTwoRequestsWithErrorInDemultiplex() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 3, false, false, mapWithErrorOn1, onMissingError);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 3, false, false, mapWithErrorOn1, onMissingError);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\");\n    }\n\n    @Test\n    public void testTwoRequestsWithEmptyResponseAndOnMissingError() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingError);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 0, onMissingError);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(IllegalStateException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertError(IllegalStateException.class);\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testTwoRequestsWithEmptyResponseAndOnMissingThrow() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingThrow);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 0, onMissingThrow);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertError(RuntimeException.class);\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testTwoRequestsWithEmptyResponseAndOnMissingComplete() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingComplete);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 0, onMissingComplete);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testTwoRequestsWithEmptyResponseAndOnMissingIgnore() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingIgnore);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 0, onMissingIgnore);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testTwoRequestsWithEmptyResponseAndOnMissingFillInStaticValue() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingFillIn);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 0, onMissingFillIn);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertValues(\"fillin\");\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"fillin\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForOneArgOnlyAndOnMissingComplete() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingComplete);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 5, onMissingComplete);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\", \"2:8\", \"2:10\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForOneArgOnlyAndOnMissingFillInStaticValue() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingFillIn);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 5, onMissingFillIn);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertValues(\"fillin\");\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\", \"2:8\", \"2:10\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForOneArgOnlyAndOnMissingIgnore() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingIgnore);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 5, onMissingIgnore);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertCompleted();\n        testSubscriber1.assertNoErrors();\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\", \"2:8\", \"2:10\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForOneArgOnlyAndOnMissingError() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingError);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 5, onMissingError);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(IllegalStateException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\", \"2:8\", \"2:10\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForOneArgOnlyAndOnMissingThrow() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 0, onMissingThrow);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 5, onMissingThrow);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\", \"2:8\", \"2:10\");\n    }\n\n    @Test\n    public void testTwoRequestsWithValuesForWrongArgs() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 3, false, false, map1To3And2To2, onMissingError);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 3, false, false, map1To3And2To2, onMissingError);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertCompleted();\n        testSubscriber2.assertNoErrors();\n        testSubscriber2.assertValues(\"2:2\", \"2:4\", \"2:6\");\n    }\n\n    @Test\n    public void testTwoRequestsWhenBatchCommandFails() {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestCollapserWithMultipleResponses(timer, 1, 3, false, true, map1To3And2To2, onMissingError);\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestCollapserWithMultipleResponses(timer, 2, 3, false, true, map1To3And2To2, onMissingError);\n\n        System.out.println(\"Starting to observe collapser1\");\n        Observable<String> result1 = collapser1.observe();\n        Observable<String> result2 = collapser2.observe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        TestSubscriber<String> testSubscriber1 = new TestSubscriber<String>();\n        result1.subscribe(testSubscriber1);\n\n        TestSubscriber<String> testSubscriber2 = new TestSubscriber<String>();\n        result2.subscribe(testSubscriber2);\n\n        testSubscriber1.awaitTerminalEvent();\n        testSubscriber2.awaitTerminalEvent();\n\n        testSubscriber1.assertError(RuntimeException.class);\n        testSubscriber1.getOnErrorEvents().get(0).printStackTrace();\n        testSubscriber1.assertNoValues();\n        testSubscriber2.assertError(RuntimeException.class);\n        testSubscriber2.assertNoValues();\n    }\n\n    @Test\n    public void testCollapserUnderConcurrency() throws InterruptedException {\n        final CollapserTimer timer = new RealCollapserTimer();\n\n        final int NUM_THREADS_SUBMITTING_WORK = 8;\n        final int NUM_REQUESTS_PER_THREAD = 8;\n\n        final CountDownLatch latch = new CountDownLatch(NUM_THREADS_SUBMITTING_WORK);\n\n        List<Runnable> runnables = new ArrayList<Runnable>();\n        final ConcurrentLinkedQueue<TestSubscriber<String>> subscribers = new ConcurrentLinkedQueue<TestSubscriber<String>>();\n\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n\n        final AtomicInteger uniqueInt = new AtomicInteger(0);\n\n        for (int i = 0; i < NUM_THREADS_SUBMITTING_WORK; i++) {\n            runnables.add(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        //System.out.println(\"Runnable starting on thread : \" + Thread.currentThread().getName());\n\n                        for (int j = 0; j < NUM_REQUESTS_PER_THREAD; j++) {\n                            HystrixObservableCollapser<String, String, String, String> collapser =\n                                    new TestCollapserWithMultipleResponses(timer, uniqueInt.getAndIncrement(), 3, false);\n                            Observable<String> o = collapser.toObservable();\n                            TestSubscriber<String> subscriber = new TestSubscriber<String>();\n                            o.subscribe(subscriber);\n                            subscribers.offer(subscriber);\n                        }\n                        //System.out.println(\"Runnable done on thread : \" + Thread.currentThread().getName());\n                    } finally {\n                        latch.countDown();\n                    }\n                }\n            });\n        }\n\n        for (Runnable r: runnables) {\n            threadPool.submit(new HystrixContextRunnable(r));\n        }\n\n        assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));\n\n        for (TestSubscriber<String> subscriber: subscribers) {\n            subscriber.awaitTerminalEvent();\n            if (subscriber.getOnErrorEvents().size() > 0) {\n                System.out.println(\"ERROR : \" + subscriber.getOnErrorEvents());\n                for (Throwable ex: subscriber.getOnErrorEvents()) {\n                    ex.printStackTrace();\n                }\n            }\n            subscriber.assertCompleted();\n            subscriber.assertNoErrors();\n            System.out.println(\"Received : \" + subscriber.getOnNextEvents());\n            subscriber.assertValueCount(3);\n        }\n\n        context.shutdown();\n    }\n\n    @Test\n    public void testConcurrencyInLoop() throws InterruptedException {\n        for (int i = 0; i < 10; i++) {\n            System.out.println(\"TRIAL : \" + i);\n            testCollapserUnderConcurrency();\n        }\n    }\n\n    @Test\n    public void testEarlyUnsubscribeExecutedViaToObservable() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.toObservable();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.toObservable();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"2\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixCollapserMetrics metrics = collapser1.getMetrics();\n        assertSame(metrics, collapser2.getMetrics());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertEquals(1, command.getNumberCollapsed()); //1 should have been removed from batch\n    }\n\n    @Test\n    public void testEarlyUnsubscribeExecutedViaObserve() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"2\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixCollapserMetrics metrics = collapser1.getMetrics();\n        assertSame(metrics, collapser2.getMetrics());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertEquals(1, command.getNumberCollapsed()); //1 should have been removed from batch\n    }\n\n    @Test\n    public void testEarlyUnsubscribeFromAllCancelsBatch() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new TestRequestCollapser(timer, 1);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new TestRequestCollapser(timer, 2);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s2.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertNull(value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndCacheHitUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s2.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertEquals(\"foo\", value1.get());\n        assertNull(value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenCacheHitAndOriginalUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"foo\", value2.get());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsOriginalAndOneCacheHitUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser3 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response3 = collapser3.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final CountDownLatch latch3 = new CountDownLatch(1);\n\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n        final AtomicReference<String> value3 = new AtomicReference<String>(null);\n\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        Subscription s3 = response3\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 Unsubscribed!\");\n                        latch3.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnCompleted\");\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnError : \" + e);\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnNext : \" + s);\n                        value3.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s3.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertEquals(\"foo\", value2.get());\n        assertNull(value3.get());\n\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n\n        HystrixInvokableInfo<?> command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().iterator().next();\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.COLLAPSED);\n        assertEquals(1, command.getNumberCollapsed()); //should only be 1 collapsed - other came from cache, then was cancelled\n    }\n\n    @Test\n    public void testRequestThenTwoCacheHitsAllUnsubscribed() throws Exception {\n        TestCollapserTimer timer = new TestCollapserTimer();\n        HystrixObservableCollapser<String, String, String, String> collapser1 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response1 = collapser1.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser2 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response2 = collapser2.observe();\n        HystrixObservableCollapser<String, String, String, String> collapser3 = new SuccessfulCacheableCollapsedCommand(timer, \"foo\", true);\n        Observable<String> response3 = collapser3.observe();\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final CountDownLatch latch3 = new CountDownLatch(1);\n\n\n        final AtomicReference<String> value1 = new AtomicReference<String>(null);\n        final AtomicReference<String> value2 = new AtomicReference<String>(null);\n        final AtomicReference<String> value3 = new AtomicReference<String>(null);\n\n\n        Subscription s1 = response1\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 Unsubscribed!\");\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s1 OnNext : \" + s);\n                        value1.set(s);\n                    }\n                });\n\n        Subscription s2 = response2\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 Unsubscribed!\");\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s2 OnNext : \" + s);\n                        value2.set(s);\n                    }\n                });\n\n        Subscription s3 = response3\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 Unsubscribed!\");\n                        latch3.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<String>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnCompleted\");\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnError : \" + e);\n                        latch3.countDown();\n                    }\n\n                    @Override\n                    public void onNext(String s) {\n                        System.out.println(System.currentTimeMillis() + \" : s3 OnNext : \" + s);\n                        value3.set(s);\n                    }\n                });\n\n        s1.unsubscribe();\n        s2.unsubscribe();\n        s3.unsubscribe();\n\n        timer.incrementTime(10); // let time pass that equals the default delay/period\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS));\n\n        assertNull(value1.get());\n        assertNull(value2.get());\n        assertNull(value3.get());\n\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    class Pair<A, B> {\n        final A a;\n        final B b;\n\n        Pair(A a, B b) {\n            this.a = a;\n            this.b = b;\n        }\n    }\n\n    class MyCommand extends HystrixObservableCommand<Pair<String, Integer>> {\n\n        private final List<String> args;\n\n        public MyCommand(List<String> args) {\n            super(HystrixObservableCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"BATCH\")));\n            this.args = args;\n        }\n\n        @Override\n        protected Observable<Pair<String, Integer>> construct() {\n            return Observable.from(args).map(new Func1<String, Pair<String, Integer>>() {\n                @Override\n                public Pair<String, Integer> call(String s) {\n                    return new Pair<String, Integer>(s, Integer.parseInt(s));\n                }\n            });\n        }\n    }\n\n    class MyCollapser extends HystrixObservableCollapser<String, Pair<String, Integer>, Integer, String> {\n\n        private final String arg;\n\n        public MyCollapser(String arg, boolean requestCachingOn) {\n            super(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                    HystrixObservableCollapser.Scope.REQUEST,\n                    new RealCollapserTimer(),\n                    HystrixCollapserProperties.Setter().withRequestCacheEnabled(requestCachingOn),\n                    HystrixCollapserMetrics.getInstance(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                            new HystrixPropertiesCollapserDefault(HystrixCollapserKey.Factory.asKey(\"UNITTEST\"),\n                                    HystrixCollapserProperties.Setter())));\n            this.arg = arg;\n        }\n\n\n        @Override\n        public String getRequestArgument() {\n            return arg;\n        }\n\n        @Override\n        protected HystrixObservableCommand<Pair<String, Integer>> createCommand(Collection<CollapsedRequest<Integer, String>> collapsedRequests) {\n            List<String> args = new ArrayList<String>();\n            for (CollapsedRequest<Integer, String> req: collapsedRequests) {\n                args.add(req.getArgument());\n            }\n\n            return new MyCommand(args);\n        }\n\n        @Override\n        protected Func1<Pair<String, Integer>, String> getBatchReturnTypeKeySelector() {\n            return new Func1<Pair<String, Integer>, String>() {\n                @Override\n                public String call(Pair<String, Integer> pair) {\n                    return pair.a;\n                }\n            };\n        }\n\n        @Override\n        protected Func1<String, String> getRequestArgumentKeySelector() {\n            return new Func1<String, String>() {\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n            };\n        }\n\n        @Override\n        protected void onMissingResponse(CollapsedRequest<Integer, String> r) {\n            r.setException(new RuntimeException(\"missing\"));\n        }\n\n        @Override\n        protected Func1<Pair<String, Integer>, Integer> getBatchReturnTypeToResponseTypeMapper() {\n            return new Func1<Pair<String, Integer>, Integer>() {\n                @Override\n                public Integer call(Pair<String, Integer> pair) {\n                    return pair.b;\n                }\n            };\n        }\n    }\n\n    @Test\n    public void testDuplicateArgumentsWithRequestCachingOn() throws Exception {\n        final int NUM = 10;\n\n        List<Observable<Integer>> observables = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM; i++) {\n            MyCollapser c = new MyCollapser(\"5\", true);\n            observables.add(c.toObservable());\n        }\n\n        List<TestSubscriber<Integer>> subscribers = new ArrayList<TestSubscriber<Integer>>();\n        for (final Observable<Integer> o: observables) {\n            final TestSubscriber<Integer> sub = new TestSubscriber<Integer>();\n            subscribers.add(sub);\n\n            o.subscribe(sub);\n        }\n\n        Thread.sleep(100);\n\n        //all subscribers should receive the same value\n        for (TestSubscriber<Integer> sub: subscribers) {\n            sub.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);\n            System.out.println(\"Subscriber received : \" + sub.getOnNextEvents());\n            sub.assertCompleted();\n            sub.assertNoErrors();\n            sub.assertValues(5);\n        }\n    }\n\n    @Test\n    public void testDuplicateArgumentsWithRequestCachingOff() throws Exception {\n        final int NUM = 10;\n\n        List<Observable<Integer>> observables = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM; i++) {\n            MyCollapser c = new MyCollapser(\"5\", false);\n            observables.add(c.toObservable());\n        }\n\n        List<TestSubscriber<Integer>> subscribers = new ArrayList<TestSubscriber<Integer>>();\n        for (final Observable<Integer> o: observables) {\n            final TestSubscriber<Integer> sub = new TestSubscriber<Integer>();\n            subscribers.add(sub);\n\n            o.subscribe(sub);\n        }\n\n        Thread.sleep(100);\n\n        AtomicInteger numErrors = new AtomicInteger(0);\n        AtomicInteger numValues = new AtomicInteger(0);\n\n        // only the first subscriber should receive the value.\n        // the others should get an error that the batch contains duplicates\n        for (TestSubscriber<Integer> sub: subscribers) {\n            sub.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);\n            if (sub.getOnCompletedEvents().isEmpty()) {\n                System.out.println(Thread.currentThread().getName() + \" Error : \" + sub.getOnErrorEvents());\n                sub.assertError(IllegalArgumentException.class);\n                sub.assertNoValues();\n                numErrors.getAndIncrement();\n\n            } else {\n                System.out.println(Thread.currentThread().getName() + \" OnNext : \" + sub.getOnNextEvents());\n                sub.assertValues(5);\n                sub.assertCompleted();\n                sub.assertNoErrors();\n                numValues.getAndIncrement();\n            }\n        }\n\n        assertEquals(1, numValues.get());\n        assertEquals(NUM - 1, numErrors.get());\n    }\n\n    protected void assertCommandExecutionEvents(HystrixInvokableInfo<?> command, HystrixEventType... expectedEventTypes) {\n        boolean emitExpected = false;\n        int expectedEmitCount = 0;\n\n        boolean fallbackEmitExpected = false;\n        int expectedFallbackEmitCount = 0;\n\n        List<HystrixEventType> condensedEmitExpectedEventTypes = new ArrayList<HystrixEventType>();\n\n        for (HystrixEventType expectedEventType: expectedEventTypes) {\n            if (expectedEventType.equals(HystrixEventType.EMIT)) {\n                if (!emitExpected) {\n                    //first EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.EMIT);\n                }\n                emitExpected = true;\n                expectedEmitCount++;\n            } else if (expectedEventType.equals(HystrixEventType.FALLBACK_EMIT)) {\n                if (!fallbackEmitExpected) {\n                    //first FALLBACK_EMIT encountered, add it to condensedEmitExpectedEventTypes\n                    condensedEmitExpectedEventTypes.add(HystrixEventType.FALLBACK_EMIT);\n                }\n                fallbackEmitExpected = true;\n                expectedFallbackEmitCount++;\n            } else {\n                condensedEmitExpectedEventTypes.add(expectedEventType);\n            }\n        }\n        List<HystrixEventType> actualEventTypes = command.getExecutionEvents();\n        assertEquals(expectedEmitCount, command.getNumberEmissions());\n        assertEquals(expectedFallbackEmitCount, command.getNumberFallbackEmissions());\n        assertEquals(condensedEmitExpectedEventTypes, actualEventTypes);\n    }\n\n    private static class TestRequestCollapser extends HystrixObservableCollapser<String, String, String, String> {\n\n        private final String value;\n        private ConcurrentLinkedQueue<HystrixObservableCommand<String>> commandsExecuted;\n\n        public TestRequestCollapser(TestCollapserTimer timer, int value) {\n            this(timer, String.valueOf(value));\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value) {\n            this(timer, value, 10000, 10);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, ConcurrentLinkedQueue<HystrixObservableCommand<String>> executionLog) {\n            this(timer, value, 10000, 10, executionLog);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, int value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(timer, String.valueOf(value), defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, null);\n        }\n\n        public TestRequestCollapser(Scope scope, TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds) {\n            this(scope, timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, null);\n        }\n\n        public TestRequestCollapser(TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds, ConcurrentLinkedQueue<HystrixObservableCommand<String>> executionLog) {\n            this(Scope.REQUEST, timer, value, defaultMaxRequestsInBatch, defaultTimerDelayInMilliseconds, executionLog);\n        }\n\n        private static HystrixCollapserMetrics createMetrics() {\n            HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"COLLAPSER_ONE\");\n            return HystrixCollapserMetrics.getInstance(key, new HystrixPropertiesCollapserDefault(key, HystrixCollapserProperties.Setter()));\n        }\n\n        public TestRequestCollapser(Scope scope, TestCollapserTimer timer, String value, int defaultMaxRequestsInBatch, int defaultTimerDelayInMilliseconds, ConcurrentLinkedQueue<HystrixObservableCommand<String>> executionLog) {\n            // use a CollapserKey based on the CollapserTimer object reference so it's unique for each timer as we don't want caching\n            // of properties to occur and we're using the default HystrixProperty which typically does caching\n            super(collapserKeyFromString(timer), scope, timer, HystrixCollapserProperties.Setter().withMaxRequestsInBatch(defaultMaxRequestsInBatch).withTimerDelayInMilliseconds(defaultTimerDelayInMilliseconds), createMetrics());\n            this.value = value;\n            this.commandsExecuted = executionLog;\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return value;\n        }\n\n        @Override\n        public HystrixObservableCommand<String> createCommand(final Collection<CollapsedRequest<String, String>> requests) {\n            /* return a mocked command */\n            HystrixObservableCommand<String> command = new TestCollapserCommand(requests);\n            if (commandsExecuted != null) {\n                commandsExecuted.add(command);\n            }\n            return command;\n        }\n\n        @Override\n        protected Func1<String, String> getBatchReturnTypeToResponseTypeMapper() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n\n        @Override\n        protected Func1<String, String> getBatchReturnTypeKeySelector() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n\n        @Override\n        protected Func1<String, String> getRequestArgumentKeySelector() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n\n        @Override\n        protected void onMissingResponse(CollapsedRequest<String, String> r) {\n            r.setException(new RuntimeException(\"missing value!\"));\n        }\n    }\n\n    private static HystrixCollapserKey collapserKeyFromString(final Object o) {\n        return new HystrixCollapserKey() {\n\n            @Override\n            public String name() {\n                return String.valueOf(o);\n            }\n\n        };\n    }\n\n    private static class TestCollapserCommand extends TestHystrixObservableCommand<String> {\n\n        private final Collection<CollapsedRequest<String, String>> requests;\n\n        TestCollapserCommand(Collection<CollapsedRequest<String, String>> requests) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionTimeoutInMilliseconds(1000)));\n            this.requests = requests;\n        }\n\n        @Override\n        protected Observable<String> construct() {\n            return Observable.create(new OnSubscribe<String>() {\n\n                @Override\n                public void call(Subscriber<? super String> s) {\n                    System.out.println(\">>> TestCollapserCommand run() ... batch size: \" + requests.size());\n                    // simulate a batch request\n                    for (CollapsedRequest<String, String> request : requests) {\n                        if (request.getArgument() == null) {\n                            throw new NullPointerException(\"Simulated Error\");\n                        }\n                        if (request.getArgument().equals(\"TIMEOUT\")) {\n                            try {\n                                Thread.sleep(200);\n                            } catch (InterruptedException e) {\n                                e.printStackTrace();\n                            }\n                        }\n                        s.onNext(request.getArgument());\n                    }\n\n                    s.onCompleted();\n                }\n\n            }).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    private static class TestCollapserWithMultipleResponses extends HystrixObservableCollapser<String, String, String, String> {\n\n        private final String arg;\n        private final static ConcurrentMap<String, Integer> emitsPerArg;\n        private final boolean commandConstructionFails;\n        private final boolean commandExecutionFails;\n        private final Func1<String, String> keyMapper;\n        private final Action1<CollapsedRequest<String, String>> onMissingResponseHandler;\n\n        private final static HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"COLLAPSER_MULTI\");\n        private final static HystrixCollapserProperties.Setter propsSetter = HystrixCollapserProperties.Setter().withMaxRequestsInBatch(10).withTimerDelayInMilliseconds(10);\n        private final static HystrixCollapserMetrics metrics = HystrixCollapserMetrics.getInstance(key, new HystrixPropertiesCollapserDefault(key, HystrixCollapserProperties.Setter()));\n\n        static {\n            emitsPerArg = new ConcurrentHashMap<String, Integer>();\n        }\n\n        public TestCollapserWithMultipleResponses(CollapserTimer timer, int arg, int numEmits, boolean commandConstructionFails) {\n            this(timer, arg, numEmits, commandConstructionFails, false, prefixMapper, onMissingComplete);\n        }\n\n        public TestCollapserWithMultipleResponses(CollapserTimer timer, int arg, int numEmits, Action1<CollapsedRequest<String, String>> onMissingHandler) {\n            this(timer, arg, numEmits, false, false, prefixMapper, onMissingHandler);\n        }\n\n        public TestCollapserWithMultipleResponses(CollapserTimer timer, int arg, int numEmits, Func1<String, String> keyMapper) {\n            this(timer, arg, numEmits, false, false, keyMapper, onMissingComplete);\n        }\n\n        public TestCollapserWithMultipleResponses(CollapserTimer timer, int arg, int numEmits, boolean commandConstructionFails, boolean commandExecutionFails, Func1<String, String> keyMapper, Action1<CollapsedRequest<String, String>> onMissingResponseHandler) {\n            super(collapserKeyFromString(timer), Scope.REQUEST, timer, propsSetter, metrics);\n            this.arg = arg + \"\";\n            emitsPerArg.put(this.arg, numEmits);\n            this.commandConstructionFails = commandConstructionFails;\n            this.commandExecutionFails = commandExecutionFails;\n            this.keyMapper = keyMapper;\n            this.onMissingResponseHandler = onMissingResponseHandler;\n        }\n\n        @Override\n        public String getRequestArgument() {\n            return arg;\n        }\n\n        @Override\n        protected HystrixObservableCommand<String> createCommand(Collection<CollapsedRequest<String, String>> collapsedRequests) {\n            assertNotNull(\"command creation should have HystrixRequestContext\", HystrixRequestContext.getContextForCurrentThread());\n            if (commandConstructionFails) {\n                throw new RuntimeException(\"Exception thrown in command construction\");\n            } else {\n                List<Integer> args = new ArrayList<Integer>();\n\n                for (CollapsedRequest<String, String> collapsedRequest : collapsedRequests) {\n                    String stringArg = collapsedRequest.getArgument();\n                    int intArg = Integer.parseInt(stringArg);\n                    args.add(intArg);\n                }\n\n                return new TestCollapserCommandWithMultipleResponsePerArgument(args, emitsPerArg, commandExecutionFails);\n            }\n        }\n\n        //Data comes back in the form: 1:1, 1:2, 1:3, 2:2, 2:4, 2:6.\n        //This method should use the first half of that string as the request arg\n        @Override\n        protected Func1<String, String> getBatchReturnTypeKeySelector() {\n            return keyMapper;\n\n        }\n\n        @Override\n        protected Func1<String, String> getRequestArgumentKeySelector() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n\n        @Override\n        protected void onMissingResponse(CollapsedRequest<String, String> r) {\n            onMissingResponseHandler.call(r);\n\n        }\n\n        @Override\n        protected Func1<String, String> getBatchReturnTypeToResponseTypeMapper() {\n            return new Func1<String, String>() {\n\n                @Override\n                public String call(String s) {\n                    return s;\n                }\n\n            };\n        }\n    }\n\n    private static class TestCollapserCommandWithMultipleResponsePerArgument extends TestHystrixObservableCommand<String> {\n\n        private final List<Integer> args;\n        private final Map<String, Integer> emitsPerArg;\n        private final boolean commandExecutionFails;\n\n        private static InspectableBuilder.TestCommandBuilder setter = testPropsBuilder();\n\n        TestCollapserCommandWithMultipleResponsePerArgument(List<Integer> args, Map<String, Integer> emitsPerArg, boolean commandExecutionFails) {\n            super(setter);\n            this.args = args;\n            this.emitsPerArg = emitsPerArg;\n            this.commandExecutionFails = commandExecutionFails;\n        }\n\n        @Override\n        protected Observable<String> construct() {\n            assertNotNull(\"Wiring the Batch command into the Observable chain should have a HystrixRequestContext\", HystrixRequestContext.getContextForCurrentThread());\n            if (commandExecutionFails) {\n                return Observable.error(new RuntimeException(\"Synthetic error while running batch command\"));\n            } else {\n                return Observable.create(new OnSubscribe<String>() {\n                    @Override\n                    public void call(Subscriber<? super String> subscriber) {\n                        try {\n                            assertNotNull(\"Executing the Batch command should have a HystrixRequestContext\", HystrixRequestContext.getContextForCurrentThread());\n                            Thread.sleep(1);\n                            for (Integer arg : args) {\n                                int numEmits = emitsPerArg.get(arg.toString());\n                                for (int j = 1; j < numEmits + 1; j++) {\n                                    subscriber.onNext(arg + \":\" + (arg * j));\n                                    Thread.sleep(1);\n                                }\n                                Thread.sleep(1);\n                            }\n                            subscriber.onCompleted();\n                        } catch (Throwable ex) {\n                            ex.printStackTrace();\n                            subscriber.onError(ex);\n                        }\n                    }\n                });\n            }\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCollapsedCommand extends TestRequestCollapser {\n\n        private final boolean cacheEnabled;\n\n        public SuccessfulCacheableCollapsedCommand(TestCollapserTimer timer, String value, boolean cacheEnabled) {\n            super(timer, value);\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return \"aCacheKey_\" + super.value;\n            else\n                return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.AbstractCommand.TryableSemaphoreActual;\nimport com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport org.junit.After;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.*;\nimport rx.Observable.OnSubscribe;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.observers.TestSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixObservableCommandTest extends CommonHystrixCommandTests<TestHystrixObservableCommand<Integer>> {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @After\n    public void cleanup() {\n        // force properties to be clean as well\n        ConfigurationManager.getConfigInstance().clear();\n\n        /*\n         * RxJava will create one worker for each processor when we schedule Observables in the\n         * Schedulers.computation(). Any leftovers here might lead to a congestion in a following\n         * thread. To ensure all existing threads have completed we now schedule some observables\n         * that will execute in distinct threads due to the latch..\n         */\n        int count = Runtime.getRuntime().availableProcessors();\n        final CountDownLatch latch = new CountDownLatch(count);\n        ArrayList<Future<Boolean>> futures = new ArrayList<Future<Boolean>>();\n        for (int i = 0; i < count; ++i) {\n            futures.add(Observable.create(new OnSubscribe<Boolean>() {\n                @Override\n                public void call(Subscriber<? super Boolean> sub) {\n                    latch.countDown();\n                    try {\n                        latch.await();\n\n                        sub.onNext(true);\n                        sub.onCompleted();\n                    } catch (InterruptedException e) {\n                        sub.onError(e);\n                    }\n                }\n            }).subscribeOn(Schedulers.computation()).toBlocking().toFuture());\n        }\n        for (Future<Boolean> future : futures) {\n            try {\n                future.get();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            } catch (ExecutionException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        //TODO commented out as it has issues when built from command-line even though it works from IDE\n        //        HystrixCommandKey key = Hystrix.getCurrentThreadExecutingCommand();\n        //        if (key != null) {\n        //            throw new IllegalStateException(\"should be null but got: \" + key);\n        //        }\n    }\n\n    class CompletableCommand extends HystrixObservableCommand<Integer> {\n\n        CompletableCommand() {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"COMPLETABLE\")));\n        }\n\n        @Override\n        protected Observable<Integer> construct() {\n            return Completable.complete().toObservable();\n        }\n    }\n\n    @Test\n    public void testCompletable() throws InterruptedException {\n\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        final HystrixObservableCommand<Integer> command = new CompletableCommand();\n\n        command.observe().subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnError : \" + e);\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer integer) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnNext : \" + integer);\n            }\n        });\n\n        latch.await();\n        assertEquals(null, command.getFailedExecutionException());\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n        assertFalse(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertNull(command.getExecutionException());\n    }\n\n    /**\n     * Test a successful semaphore-isolated command execution.\n     */\n    @Test\n    public void testSemaphoreObserveSuccess() {\n        testObserveSuccess(ExecutionIsolationStrategy.SEMAPHORE);\n    }\n\n    /**\n     * Test a successful thread-isolated command execution.\n     */\n    @Test\n    public void testThreadObserveSuccess() {\n        testObserveSuccess(ExecutionIsolationStrategy.THREAD);\n    }\n\n    private void testObserveSuccess(ExecutionIsolationStrategy isolationStrategy) {\n        try {\n            TestHystrixObservableCommand<Boolean> command = new SuccessfulTestCommand(isolationStrategy);\n            assertEquals(true, command.observe().toBlocking().single());\n\n            assertEquals(null, command.getFailedExecutionException());\n\n            assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n            assertTrue(command.isSuccessfulExecution());\n            assertFalse(command.isResponseFromFallback());\n            assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n            assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n            assertNull(command.getExecutionException());\n            assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    /**\n     * Test that a semaphore command can not be executed multiple times.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveMultipleTimes() {\n        testObserveMultipleTimes(ExecutionIsolationStrategy.SEMAPHORE);\n    }\n\n    /**\n     * Test that a thread command can not be executed multiple times.\n     */\n    @Test\n    public void testThreadIsolatedObserveMultipleTimes() {\n        testObserveMultipleTimes(ExecutionIsolationStrategy.THREAD);\n    }\n\n    private void testObserveMultipleTimes(ExecutionIsolationStrategy isolationStrategy) {\n        SuccessfulTestCommand command = new SuccessfulTestCommand(isolationStrategy);\n        assertFalse(command.isExecutionComplete());\n        // first should succeed\n        assertEquals(true, command.observe().toBlocking().single());\n        assertTrue(command.isExecutionComplete());\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n        assertFalse(command.isResponseFromFallback());\n        assertNull(command.getExecutionException());\n\n        try {\n            // second should fail\n            command.observe().toBlocking().single();\n            fail(\"we should not allow this ... it breaks the state of request logs\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            // we want to get here\n        }\n\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n        assertSaneHystrixRequestLog(1);\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n    }\n\n    /**\n     * Test a semaphore command execution that throws an HystrixException synchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveKnownSyncFailureWithNoFallback() {\n        testObserveKnownFailureWithNoFallback(ExecutionIsolationStrategy.SEMAPHORE, false);\n    }\n\n    /**\n     * Test a semaphore command execution that throws an HystrixException asynchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveKnownAsyncFailureWithNoFallback() {\n        testObserveKnownFailureWithNoFallback(ExecutionIsolationStrategy.SEMAPHORE, true);\n    }\n\n    /**\n     * Test a thread command execution that throws an HystrixException synchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveKnownSyncFailureWithNoFallback() {\n        testObserveKnownFailureWithNoFallback(ExecutionIsolationStrategy.THREAD, false);\n    }\n\n    /**\n     * Test a thread command execution that throws an HystrixException asynchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveKnownAsyncFailureWithNoFallback() {\n        testObserveKnownFailureWithNoFallback(ExecutionIsolationStrategy.THREAD, true);\n    }\n\n    private void testObserveKnownFailureWithNoFallback(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        TestHystrixObservableCommand<Boolean> command = new KnownFailureTestCommandWithoutFallback(circuitBreaker, isolationStrategy, asyncException);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertNotNull(e.getFallbackException());\n            assertNotNull(e.getImplementingClass());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should always get an HystrixRuntimeException when an error occurs.\");\n        }\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertFalse(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution that throws an unknown exception (not HystrixException) synchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveUnknownSyncFailureWithNoFallback() {\n        testObserveUnknownFailureWithNoFallback(ExecutionIsolationStrategy.SEMAPHORE, false);\n    }\n\n    /**\n     * Test a semaphore command execution that throws an unknown exception (not HystrixException) asynchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveUnknownAsyncFailureWithNoFallback() {\n        testObserveUnknownFailureWithNoFallback(ExecutionIsolationStrategy.SEMAPHORE, true);\n    }\n\n    /**\n     * Test a thread command execution that throws an unknown exception (not HystrixException) synchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveUnknownSyncFailureWithNoFallback() {\n        testObserveUnknownFailureWithNoFallback(ExecutionIsolationStrategy.THREAD, false);\n    }\n\n    /**\n     * Test a thread command execution that throws an unknown exception (not HystrixException) asynchronously and didn't implement getFallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveUnknownAsyncFailureWithNoFallback() {\n        testObserveUnknownFailureWithNoFallback(ExecutionIsolationStrategy.THREAD, true);\n    }\n\n    private void testObserveUnknownFailureWithNoFallback(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n        TestHystrixObservableCommand<Boolean> command = new UnknownFailureTestCommandWithoutFallback(isolationStrategy, asyncException);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertNotNull(e.getFallbackException());\n            assertNotNull(e.getImplementingClass());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should always get an HystrixRuntimeException when an error occurs.\");\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertFalse(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertNotNull(command.getExecutionException());\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution that fails synchronously but has a fallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveSyncFailureWithFallback() {\n        testObserveFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, false);\n    }\n\n    /**\n     * Test a semaphore command execution that fails asynchronously but has a fallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveAsyncFailureWithFallback() {\n        testObserveFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, true);\n    }\n\n    /**\n     * Test a thread command execution that fails synchronously but has a fallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveSyncFailureWithFallback() {\n        testObserveFailureWithFallback(ExecutionIsolationStrategy.THREAD, false);\n    }\n\n    /**\n     * Test a thread command execution that fails asynchronously but has a fallback.\n     */\n    @Test\n    public void testThreadIsolatedObserveAsyncFailureWithFallback() {\n        testObserveFailureWithFallback(ExecutionIsolationStrategy.THREAD, true);\n    }\n\n    private void testObserveFailureWithFallback(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n        TestHystrixObservableCommand<Boolean> command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), isolationStrategy, asyncException);\n        try {\n            assertEquals(false, command.observe().toBlocking().single());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertEquals(\"we failed with a simulated issue\", command.getFailedExecutionException().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertTrue(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertNotNull(command.getExecutionException());\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a command execution that fails synchronously, has getFallback implemented but that fails as well (synchronously).\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveSyncFailureWithSyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, false, false);\n    }\n\n    /**\n     * Test a command execution that fails synchronously, has getFallback implemented but that fails as well (asynchronously).\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveSyncFailureWithAsyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, false, true);\n    }\n\n    /**\n     * Test a command execution that fails asynchronously, has getFallback implemented but that fails as well (synchronously).\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveAyncFailureWithSyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, true, false);\n    }\n\n    /**\n     * Test a command execution that fails asynchronously, has getFallback implemented but that fails as well (asynchronously).\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveAsyncFailureWithAsyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, true, true);\n    }\n\n    /**\n     * Test a command execution that fails synchronously, has getFallback implemented but that fails as well (synchronously).\n     */\n    @Test\n    public void testThreadIsolatedObserveSyncFailureWithSyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.THREAD, false, false);\n    }\n\n    /**\n     * Test a command execution that fails synchronously, has getFallback implemented but that fails as well (asynchronously).\n     */\n    @Test\n    public void testThreadIsolatedObserveSyncFailureWithAsyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.THREAD, true, false);\n    }\n\n    /**\n     * Test a command execution that fails asynchronously, has getFallback implemented but that fails as well (synchronously).\n     */\n    @Test\n    public void testThreadIsolatedObserveAyncFailureWithSyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.THREAD, false, true);\n    }\n\n    /**\n     * Test a command execution that fails asynchronously, has getFallback implemented but that fails as well (asynchronously).\n     */\n    @Test\n    public void testThreadIsolatedObserveAsyncFailureWithAsyncFallbackFailure() {\n        testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy.THREAD, true, true);\n    }\n\n\n    private void testObserveFailureWithFallbackFailure(ExecutionIsolationStrategy isolationStrategy, boolean asyncFallbackException, boolean asyncConstructException) {\n        TestHystrixObservableCommand<Boolean> command = new KnownFailureTestCommandWithFallbackFailure(new TestCircuitBreaker(), isolationStrategy, asyncConstructException, asyncFallbackException);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (HystrixRuntimeException e) {\n            System.out.println(\"------------------------------------------------\");\n            e.printStackTrace();\n            System.out.println(\"------------------------------------------------\");\n            assertNotNull(e.getFallbackException());\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertFalse(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_FAILURE);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertNotNull(command.getExecutionException());\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution that times out with a fallback and eventually succeeds.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveTimeoutWithSuccessAndFallback() {\n        testObserveFailureWithTimeoutAndFallback(ExecutionIsolationStrategy.SEMAPHORE, TestHystrixObservableCommand.ExecutionResult.MULTIPLE_EMITS_THEN_SUCCESS);\n    }\n\n    /**\n     * Test a semaphore command execution that times out with a fallback and eventually fails.\n     */\n    @Test\n    public void testSemaphoreIsolatedObserveTimeoutWithFailureAndFallback() {\n        testObserveFailureWithTimeoutAndFallback(ExecutionIsolationStrategy.SEMAPHORE, TestHystrixObservableCommand.ExecutionResult.MULTIPLE_EMITS_THEN_FAILURE);\n    }\n\n    /**\n     * Test a thread command execution that times out with a fallback and eventually succeeds.\n     */\n    @Test\n    public void testThreadIsolatedObserveTimeoutWithSuccessAndFallback() {\n        testObserveFailureWithTimeoutAndFallback(ExecutionIsolationStrategy.THREAD, TestHystrixObservableCommand.ExecutionResult.MULTIPLE_EMITS_THEN_SUCCESS);\n    }\n\n    /**\n     * Test a thread command execution that times out with a fallback and eventually fails.\n     */\n    @Test\n    public void testThreadIsolatedObserveTimeoutWithFailureAndFallback() {\n        testObserveFailureWithTimeoutAndFallback(ExecutionIsolationStrategy.THREAD, TestHystrixObservableCommand.ExecutionResult.MULTIPLE_EMITS_THEN_FAILURE);\n    }\n\n    private void testObserveFailureWithTimeoutAndFallback(ExecutionIsolationStrategy isolationStrategy, TestHystrixObservableCommand.ExecutionResult executionResult) {\n        TestHystrixObservableCommand<Integer> command = getCommand(isolationStrategy, executionResult, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 100);\n        long observedCommandDuration = 0;\n        try {\n            long startTime = System.currentTimeMillis();\n            assertEquals(FlexibleTestHystrixObservableCommand.FALLBACK_VALUE, command.observe().toBlocking().single());\n            observedCommandDuration = System.currentTimeMillis() - startTime;\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertNull(command.getFailedExecutionException());\n        assertNotNull(command.getExecutionException());\n\n        System.out.println(\"Command time : \" + command.getExecutionTimeInMilliseconds());\n        System.out.println(\"Observed command time : \" + observedCommandDuration);\n        assertTrue(command.getExecutionTimeInMilliseconds() >= 100);\n        assertTrue(observedCommandDuration >= 100);\n        assertTrue(command.getExecutionTimeInMilliseconds() < 1000);\n        assertTrue(observedCommandDuration < 1000);\n        assertFalse(command.isFailedExecution());\n        assertTrue(command.isResponseFromFallback());\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testObserveOnImmediateSchedulerByDefaultForSemaphoreIsolation() throws Exception {\n\n        final AtomicReference<Thread> commandThread = new AtomicReference<Thread>();\n        final AtomicReference<Thread> subscribeThread = new AtomicReference<Thread>();\n\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder()\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                commandThread.set(Thread.currentThread());\n                return Observable.just(true);\n            }\n        };\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        command.toObservable().subscribe(new Observer<Boolean>() {\n\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                latch.countDown();\n                e.printStackTrace();\n\n            }\n\n            @Override\n            public void onNext(Boolean args) {\n                subscribeThread.set(Thread.currentThread());\n            }\n        });\n\n        if (!latch.await(2000, TimeUnit.MILLISECONDS)) {\n            fail(\"timed out\");\n        }\n\n        assertNotNull(commandThread.get());\n        assertNotNull(subscribeThread.get());\n\n        System.out.println(\"Command Thread: \" + commandThread.get());\n        System.out.println(\"Subscribe Thread: \" + subscribeThread.get());\n\n        String mainThreadName = Thread.currentThread().getName();\n\n        // semaphore should be on the calling thread\n        assertTrue(commandThread.get().getName().equals(mainThreadName));\n        System.out.println(\"testObserveOnImmediateSchedulerByDefaultForSemaphoreIsolation: \" + subscribeThread.get() + \" => \" + mainThreadName);\n        assertTrue(subscribeThread.get().getName().equals(mainThreadName));\n\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertSaneHystrixRequestLog(1);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertNull(command.getExecutionException());\n        assertFalse(command.isResponseFromFallback());\n    }\n\n    /**\n     * Test that the circuit-breaker will 'trip' and prevent command execution on subsequent calls.\n     */\n    @Test\n    public void testCircuitBreakerTripsAfterFailures() throws InterruptedException {\n        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"KnownFailureTestCommandWithFallback\");\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(commandKey);\n        /* fail 3 times and then it should trip the circuit and stop executing */\n        // failure 1\n        KnownFailureTestCommandWithFallback attempt1 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        attempt1.observe().toBlocking().single();\n        Thread.sleep(100);\n        assertTrue(attempt1.isResponseFromFallback());\n        assertFalse(attempt1.isCircuitBreakerOpen());\n        assertFalse(attempt1.isResponseShortCircuited());\n\n        // failure 2\n        KnownFailureTestCommandWithFallback attempt2 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        attempt2.observe().toBlocking().single();\n        Thread.sleep(100);\n        assertTrue(attempt2.isResponseFromFallback());\n        assertFalse(attempt2.isCircuitBreakerOpen());\n        assertFalse(attempt2.isResponseShortCircuited());\n\n        // failure 3\n        KnownFailureTestCommandWithFallback attempt3 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        attempt3.observe().toBlocking().single();\n        Thread.sleep(100);\n        assertTrue(attempt3.isResponseFromFallback());\n        assertFalse(attempt3.isResponseShortCircuited());\n        // it should now be 'open' and prevent further executions\n        assertTrue(attempt3.isCircuitBreakerOpen());\n\n        // attempt 4\n        KnownFailureTestCommandWithFallback attempt4 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        attempt4.observe().toBlocking().single();\n        Thread.sleep(100);\n        assertTrue(attempt4.isResponseFromFallback());\n        // this should now be true as the response will be short-circuited\n        assertTrue(attempt4.isResponseShortCircuited());\n        // this should remain open\n        assertTrue(attempt4.isCircuitBreakerOpen());\n\n        assertCommandExecutionEvents(attempt1, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt2, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt3, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(attempt4, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    /**\n     * Test that the circuit-breaker being disabled doesn't wreak havoc.\n     */\n    @Test\n    public void testExecutionSuccessWithCircuitBreakerDisabled() {\n        TestHystrixObservableCommand<Boolean> command = new TestCommandWithoutCircuitBreaker();\n        try {\n            assertEquals(true, command.observe().toBlocking().single());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertNull(command.getExecutionException());\n    }\n\n    /**\n     * Test a command execution timeout where the command didn't implement getFallback.\n     */\n    @Test\n    public void testExecutionTimeoutWithNoFallbackUsingSemaphoreIsolation() {\n        TestHystrixObservableCommand<Integer> command = getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 100);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n\n        assertTrue(command.isResponseTimedOut());\n        assertFalse(command.isResponseFromFallback());\n        assertFalse(command.isResponseRejected());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n    }\n\n    /**\n     * Test a command execution timeout where the command implemented getFallback.\n     */\n    @Test\n    public void testExecutionTimeoutWithFallbackUsingSemaphoreIsolation() {\n        TestHystrixObservableCommand<Integer> command = getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 50);\n        try {\n            assertEquals(FlexibleTestHystrixObservableCommand.FALLBACK_VALUE, command.observe().toBlocking().single());\n            // the time should be 50+ since we timeout at 50ms\n            assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n            assertTrue(command.isResponseTimedOut());\n            assertTrue(command.isResponseFromFallback());\n            assertNotNull(command.getExecutionException());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n    }\n\n    /**\n     * Test a command execution timeout where the command implemented getFallback but it fails.\n     */\n    @Test\n    public void testExecutionTimeoutFallbackFailureUsingSemaphoreIsolation() {\n        TestHystrixObservableCommand<Integer> command = getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 500, AbstractTestHystrixCommand.FallbackResult.FAILURE, 200);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e instanceof HystrixRuntimeException) {\n                e.printStackTrace();\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n                assertNotNull(command.getExecutionException());\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n        // the time should be 200+ since we timeout at 200ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 200);\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_FAILURE);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution timeout where the command didn't implement getFallback.\n     */\n    @Test\n    public void testSemaphoreExecutionTimeoutWithNoFallback() {\n        testExecutionTimeoutWithNoFallback(ExecutionIsolationStrategy.SEMAPHORE);\n    }\n\n    /**\n     * Test a thread command execution timeout where the command didn't implement getFallback.\n     */\n    @Test\n    public void testThreadExecutionTimeoutWithNoFallback() {\n        testExecutionTimeoutWithNoFallback(ExecutionIsolationStrategy.THREAD);\n    }\n\n    private void testExecutionTimeoutWithNoFallback(ExecutionIsolationStrategy isolationStrategy) {\n        TestHystrixObservableCommand<Integer> command = getCommand(isolationStrategy, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 50);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n\n        assertTrue(command.isResponseTimedOut());\n        assertFalse(command.isResponseFromFallback());\n        assertFalse(command.isResponseRejected());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution timeout where the command implemented getFallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedExecutionTimeoutWithSuccessfulFallback() {\n        testExecutionTimeoutWithSuccessfulFallback(ExecutionIsolationStrategy.SEMAPHORE);\n    }\n\n    /**\n     * Test a thread command execution timeout where the command implemented getFallback.\n     */\n    @Test\n    public void testThreadIsolatedExecutionTimeoutWithSuccessfulFallback() {\n        testExecutionTimeoutWithSuccessfulFallback(ExecutionIsolationStrategy.THREAD);\n    }\n\n    private void testExecutionTimeoutWithSuccessfulFallback(ExecutionIsolationStrategy isolationStrategy) {\n        TestHystrixObservableCommand<Integer> command = getCommand(isolationStrategy, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 100);\n        try {\n            assertEquals(FlexibleTestHystrixObservableCommand.FALLBACK_VALUE, command.observe().toBlocking().single());\n            // the time should be 50+ since we timeout at 50ms\n            assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n            assertTrue(command.isResponseTimedOut());\n            assertTrue(command.isResponseFromFallback());\n            assertNotNull(command.getExecutionException());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test a semaphore command execution timeout where the command implemented getFallback but it fails synchronously.\n     */\n    @Test\n    public void testSemaphoreExecutionTimeoutSyncFallbackFailure() {\n        testExecutionTimeoutFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, false);\n    }\n\n    /**\n     * Test a semaphore command execution timeout where the command implemented getFallback but it fails asynchronously.\n     */\n    @Test\n    public void testSemaphoreExecutionTimeoutAsyncFallbackFailure() {\n        testExecutionTimeoutFallbackFailure(ExecutionIsolationStrategy.SEMAPHORE, true);\n    }\n\n    /**\n     * Test a thread command execution timeout where the command implemented getFallback but it fails synchronously.\n     */\n    @Test\n    public void testThreadExecutionTimeoutSyncFallbackFailure() {\n        testExecutionTimeoutFallbackFailure(ExecutionIsolationStrategy.THREAD, false);\n    }\n\n    /**\n     * Test a thread command execution timeout where the command implemented getFallback but it fails asynchronously.\n     */\n    @Test\n    public void testThreadExecutionTimeoutAsyncFallbackFailure() {\n        testExecutionTimeoutFallbackFailure(ExecutionIsolationStrategy.THREAD, true);\n    }\n    private void testExecutionTimeoutFallbackFailure(ExecutionIsolationStrategy isolationStrategy, boolean asyncFallbackException) {\n        TestHystrixObservableCommand<Integer> command = getCommand(isolationStrategy, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.FAILURE, 100);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we shouldn't get here\");\n        } catch (Exception e) {\n            if (e instanceof HystrixRuntimeException) {\n                HystrixRuntimeException de = (HystrixRuntimeException) e;\n                assertNotNull(de.getFallbackException());\n                assertFalse(de.getFallbackException() instanceof UnsupportedOperationException);\n                assertNotNull(de.getImplementingClass());\n                assertNotNull(de.getCause());\n                assertTrue(de.getCause() instanceof TimeoutException);\n                assertNotNull(command.getExecutionException());\n            } else {\n                fail(\"the exception should be HystrixRuntimeException\");\n            }\n        }\n        // the time should be 50+ since we timeout at 50ms\n        assertTrue(\"Execution Time is: \" + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50);\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_FAILURE);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertEquals(isolationStrategy.equals(ExecutionIsolationStrategy.THREAD), command.isExecutedInThread());\n    }\n\n    /**\n     * Test that the circuit-breaker counts a command execution timeout as a 'timeout' and not just failure.\n     */\n    @Test\n    public void testShortCircuitFallbackCounter() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true);\n        KnownFailureTestCommandWithFallback command1 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        KnownFailureTestCommandWithFallback command2 = new KnownFailureTestCommandWithFallback(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE, true);\n        try {\n            command1.observe().toBlocking().single();\n            command2.observe().toBlocking().single();\n\n            // will be -1 because it never attempted execution\n            assertEquals(-1, command2.getExecutionTimeInMilliseconds());\n            assertTrue(command2.isResponseShortCircuited());\n            assertFalse(command2.isResponseTimedOut());\n            assertNotNull(command2.getExecutionException());\n            // semaphore isolated\n            assertFalse(command2.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testExecutionSemaphoreWithObserve() {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        TestSemaphoreCommand command1 = new TestSemaphoreCommand(circuitBreaker, 1, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n\n        // single thread should work\n        try {\n            boolean result = command1.observe().toBlocking().toFuture().get();\n            assertTrue(result);\n        } catch (Exception e) {\n            // we shouldn't fail on this one\n            throw new RuntimeException(e);\n        }\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TryableSemaphoreActual semaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        final TestSemaphoreCommand command2 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    command2.observe().toBlocking().toFuture().get();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        final TestSemaphoreCommand command3 = new TestSemaphoreCommand(circuitBreaker, semaphore, 200, TestSemaphoreCommand.RESULT_SUCCESS, TestSemaphoreCommand.FALLBACK_NOT_IMPLEMENTED);\n        Runnable r3 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    command3.observe().toBlocking().toFuture().get();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore\n        Thread t2 = new Thread(r2);\n        Thread t3 = new Thread(r3);\n\n        t2.start();\n        try {\n            Thread.sleep(100);\n        } catch (Throwable ex) {\n            fail(ex.getMessage());\n        }\n\n        t3.start();\n        try {\n            t2.join();\n            t3.join();\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"failed waiting on threads\");\n        }\n\n        if (!exceptionReceived.get()) {\n            fail(\"We expected an exception on the 2nd get\");\n        }\n\n        System.out.println(\"CMD1 : \" + command1.getExecutionEvents());\n        System.out.println(\"CMD2 : \" + command2.getExecutionEvents());\n        System.out.println(\"CMD3 : \" + command3.getExecutionEvents());\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    @Test\n    public void testRejectedExecutionSemaphoreWithFallback() {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        final ArrayBlockingQueue<Boolean> results = new ArrayBlockingQueue<Boolean>(2);\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n\n        final TestSemaphoreCommandWithFallback command1 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r1 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command1.observe().toBlocking().single());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        final TestSemaphoreCommandWithFallback command2 = new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false);\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    results.add(command2.observe().toBlocking().single());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n\n        });\n\n        // 2 threads, the second should be rejected by the semaphore and return fallback\n        Thread t1 = new Thread(r1);\n        Thread t2 = new Thread(r2);\n\n        t1.start();\n        try {\n            //give t1 a headstart\n            Thread.sleep(50);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n        t2.start();\n        try {\n            t1.join();\n            t2.join();\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"failed waiting on threads\");\n        }\n\n        if (exceptionReceived.get()) {\n            fail(\"We should have received a fallback response\");\n        }\n\n        // both threads should have returned values\n        assertEquals(2, results.size());\n        // should contain both a true and false result\n        assertTrue(results.contains(Boolean.TRUE));\n        assertTrue(results.contains(Boolean.FALSE));\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command1.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testSemaphorePermitsInUse() {\n        // this semaphore will be shared across multiple command instances\n        final TryableSemaphoreActual sharedSemaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(3));\n\n        // creates thread using isolated semaphore\n        final TryableSemaphoreActual isolatedSemaphore =\n                new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        //used to wait until all commands are started\n        final CountDownLatch startLatch = new CountDownLatch((sharedSemaphore.numberOfPermits.get()) * 2 + 1);\n\n        // used to signal that all command can finish\n        final CountDownLatch sharedLatch = new CountDownLatch(1);\n        final CountDownLatch isolatedLatch = new CountDownLatch(1);\n\n        final List<HystrixObservableCommand<Boolean>> commands = new ArrayList<HystrixObservableCommand<Boolean>>();\n        final List<Observable<Boolean>> results = new ArrayList<Observable<Boolean>>();\n\n        HystrixObservableCommand<Boolean> isolated = new LatchedSemaphoreCommand(\"ObservableCommand-Isolated\", circuitBreaker, isolatedSemaphore, startLatch, isolatedLatch);\n        commands.add(isolated);\n\n        for (int s = 0; s < sharedSemaphore.numberOfPermits.get() * 2; s++) {\n            HystrixObservableCommand<Boolean> shared = new LatchedSemaphoreCommand(\"ObservableCommand-Shared\", circuitBreaker, sharedSemaphore, startLatch, sharedLatch);\n            commands.add(shared);\n            Observable<Boolean> result = shared.toObservable();\n            results.add(result);\n        }\n\n        Observable<Boolean> isolatedResult = isolated.toObservable();\n        results.add(isolatedResult);\n\n        // verifies no permits in use before starting commands\n        assertEquals(\"before commands start, shared semaphore should be unused\", 0, sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"before commands start, isolated semaphore should be unused\", 0, isolatedSemaphore.getNumberOfPermitsUsed());\n\n        final CountDownLatch allTerminal = new CountDownLatch(1);\n\n        Observable.merge(results)\n                .subscribeOn(Schedulers.newThread())\n                .subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(Thread.currentThread().getName() + \" OnCompleted\");\n                        allTerminal.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(Thread.currentThread().getName() + \" OnError : \" + e);\n                        allTerminal.countDown();\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(Thread.currentThread().getName() + \" OnNext : \" + b);\n                    }\n                });\n\n        try {\n            assertTrue(startLatch.await(20, TimeUnit.SECONDS));\n        } catch (Throwable ex) {\n            fail(ex.getMessage());\n        }\n\n        // verifies that all semaphores are in use\n        assertEquals(\"immediately after command start, all shared semaphores should be in-use\",\n                sharedSemaphore.numberOfPermits.get().longValue(), sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"immediately after command start, isolated semaphore should be in-use\",\n                isolatedSemaphore.numberOfPermits.get().longValue(), isolatedSemaphore.getNumberOfPermitsUsed());\n\n        // signals commands to finish\n        sharedLatch.countDown();\n        isolatedLatch.countDown();\n\n        try {\n            assertTrue(allTerminal.await(5000, TimeUnit.MILLISECONDS));\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"failed waiting on commands\");\n        }\n\n        // verifies no permits in use after finishing threads\n        assertEquals(\"after all threads have finished, no shared semaphores should be in-use\", 0, sharedSemaphore.getNumberOfPermitsUsed());\n        assertEquals(\"after all threads have finished, isolated semaphore not in-use\", 0, isolatedSemaphore.getNumberOfPermitsUsed());\n\n        // verifies that some executions failed\n        int numSemaphoreRejected = 0;\n        for (HystrixObservableCommand<Boolean> cmd: commands) {\n            if (cmd.isResponseSemaphoreRejected()) {\n                numSemaphoreRejected++;\n            }\n        }\n        assertEquals(\"expected some of shared semaphore commands to get rejected\", sharedSemaphore.numberOfPermits.get().longValue(), numSemaphoreRejected);\n    }\n\n    /**\n     * Test that HystrixOwner can be passed in dynamically.\n     */\n    @Test\n    public void testDynamicOwner() {\n        try {\n            TestHystrixObservableCommand<Boolean> command = new DynamicOwnerTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE);\n            assertEquals(true, command.observe().toBlocking().single());\n            assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    /**\n     * Test a successful command execution.\n     */\n    @Test\n    public void testDynamicOwnerFails() {\n        try {\n            TestHystrixObservableCommand<Boolean> command = new DynamicOwnerTestCommand(null);\n            assertEquals(true, command.observe().toBlocking().single());\n            fail(\"we should have thrown an exception as we need an owner\");\n\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n\n            assertEquals(0, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        } catch (Exception e) {\n            // success if we get here\n        }\n    }\n\n    /**\n     * Test that HystrixCommandKey can be passed in dynamically.\n     */\n    @Test\n    public void testDynamicKey() {\n        try {\n            DynamicOwnerAndKeyTestCommand command1 = new DynamicOwnerAndKeyTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE, InspectableBuilder.CommandKeyForUnitTest.KEY_ONE);\n            assertEquals(true, command1.observe().toBlocking().single());\n            DynamicOwnerAndKeyTestCommand command2 = new DynamicOwnerAndKeyTestCommand(InspectableBuilder.CommandGroupForUnitTest.OWNER_ONE, InspectableBuilder.CommandKeyForUnitTest.KEY_TWO);\n            assertEquals(true, command2.observe().toBlocking().single());\n\n            // 2 different circuit breakers should be created\n            assertNotSame(command1.getCircuitBreaker(), command2.getCircuitBreaker());\n\n            // semaphore isolated\n            assertFalse(command1.isExecutedInThread());\n\n            assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    /**\n     * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future\n     */\n    @Test\n    public void testRequestCache1UsingThreadIsolation() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.observe().toBlocking().toFuture();\n        Future<String> f2 = command2.observe().toBlocking().toFuture();\n\n        try {\n            assertEquals(\"A\", f1.get());\n            assertEquals(\"A\", f2.get());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        assertTrue(command1.executed);\n        // the second one should not have executed as it should have received the cached value instead\n        assertFalse(command2.executed);\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertTrue(command1.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command1.isResponseFromCache());\n        assertNull(command1.getExecutionException());\n\n        // the execution log for command2 should show it came from cache\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertTrue(command2.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command2.isResponseFromCache());\n        assertNull(command2.getExecutionException());\n\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test Request scoped caching doesn't prevent different ones from executing\n     */\n    @Test\n    public void testRequestCache2UsingThreadIsolation() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"B\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.observe().toBlocking().toFuture();\n        Future<String> f2 = command2.observe().toBlocking().toFuture();\n\n        try {\n            assertEquals(\"A\", f1.get());\n            assertEquals(\"B\", f2.get());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertTrue(command2.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command2.isResponseFromCache());\n\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testRequestCache3UsingThreadIsolation() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"B\");\n        SuccessfulCacheableCommand<String> command3 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.observe().toBlocking().toFuture();\n        Future<String> f2 = command2.observe().toBlocking().toFuture();\n        Future<String> f3 = command3.observe().toBlocking().toFuture();\n\n        try {\n            assertEquals(\"A\", f1.get());\n            assertEquals(\"B\", f2.get());\n            assertEquals(\"A\", f3.get());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // but the 3rd should come from cache\n        assertFalse(command3.executed);\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertTrue(command3.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command3.isResponseFromCache());\n\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /**\n     * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future\n     */\n    @Test\n    public void testRequestCacheWithSlowExecution() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SlowCacheableCommand command1 = new SlowCacheableCommand(circuitBreaker, \"A\", 200);\n        SlowCacheableCommand command2 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n        SlowCacheableCommand command3 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n        SlowCacheableCommand command4 = new SlowCacheableCommand(circuitBreaker, \"A\", 100);\n\n        Future<String> f1 = command1.observe().toBlocking().toFuture();\n        Future<String> f2 = command2.observe().toBlocking().toFuture();\n        Future<String> f3 = command3.observe().toBlocking().toFuture();\n        Future<String> f4 = command4.observe().toBlocking().toFuture();\n\n        try {\n            assertEquals(\"A\", f2.get());\n            assertEquals(\"A\", f3.get());\n            assertEquals(\"A\", f4.get());\n\n            assertEquals(\"A\", f1.get());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        assertTrue(command1.executed);\n        // the second one should not have executed as it should have received the cached value instead\n        assertFalse(command2.executed);\n        assertFalse(command3.executed);\n        assertFalse(command4.executed);\n\n        // the execution log for command1 should show an EMIT and a SUCCESS\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertTrue(command1.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command1.isResponseFromCache());\n\n        // the execution log for command2 should show it came from cache\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertTrue(command2.getExecutionTimeInMilliseconds() == -1);\n        assertTrue(command2.isResponseFromCache());\n\n        assertCommandExecutionEvents(command3, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertTrue(command3.isResponseFromCache());\n        assertTrue(command3.getExecutionTimeInMilliseconds() == -1);\n\n        assertCommandExecutionEvents(command4, HystrixEventType.EMIT, HystrixEventType.SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertTrue(command4.isResponseFromCache());\n        assertTrue(command4.getExecutionTimeInMilliseconds() == -1);\n\n        assertSaneHystrixRequestLog(4);\n\n        // semaphore isolated\n        assertFalse(command1.isExecutedInThread());\n        assertFalse(command2.isExecutedInThread());\n        assertFalse(command3.isExecutedInThread());\n        assertFalse(command4.isExecutedInThread());\n    }\n\n    /**\n     * Test Request scoped caching with a mixture of commands\n     */\n    @Test\n    public void testNoRequestCache3UsingThreadIsolation() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        SuccessfulCacheableCommand<String> command1 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"A\");\n        SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"B\");\n        SuccessfulCacheableCommand<String> command3 = new SuccessfulCacheableCommand<String>(circuitBreaker, false, \"A\");\n\n        assertTrue(command1.isCommandRunningInThread());\n\n        Future<String> f1 = command1.observe().toBlocking().toFuture();\n        Future<String> f2 = command2.observe().toBlocking().toFuture();\n        Future<String> f3 = command3.observe().toBlocking().toFuture();\n\n        try {\n            assertEquals(\"A\", f1.get());\n            assertEquals(\"B\", f2.get());\n            assertEquals(\"A\", f3.get());\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        assertTrue(command1.executed);\n        // both should execute as they are different\n        assertTrue(command2.executed);\n        // this should also execute since we disabled the cache\n        assertTrue(command3.executed);\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n\n        // thread isolated\n        assertTrue(command1.isExecutedInThread());\n        assertTrue(command2.isExecutedInThread());\n        assertTrue(command3.isExecutedInThread());\n    }\n\n    @Test\n    public void testNoRequestCacheOnTimeoutThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        NoRequestCacheTimeoutWithoutFallback r1 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            System.out.println(\"r1 value: \" + r1.observe().toBlocking().single());\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r1.isResponseTimedOut());\n            // what we want\n        }\n\n        NoRequestCacheTimeoutWithoutFallback r2 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r2.observe().toBlocking().single();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r2.isResponseTimedOut());\n            // what we want\n        }\n\n        NoRequestCacheTimeoutWithoutFallback r3 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        Future<Boolean> f3 = r3.observe().toBlocking().toFuture();\n        try {\n            f3.get();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            assertTrue(r3.isResponseTimedOut());\n            // what we want\n        }\n\n        Thread.sleep(500); // timeout on command is set to 200ms\n\n        NoRequestCacheTimeoutWithoutFallback r4 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r4.observe().toBlocking().single();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertTrue(r4.isResponseTimedOut());\n            assertFalse(r4.isResponseFromFallback());\n            // what we want\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    @Test\n    public void testRequestCacheOnTimeoutCausesNullPointerException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        RequestCacheNullPointerExceptionCase command1 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command2 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command3 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command4 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        RequestCacheNullPointerExceptionCase command5 = new RequestCacheNullPointerExceptionCase(circuitBreaker);\n        // Expect it to time out - all results should be false\n        assertFalse(command1.observe().toBlocking().single());\n        assertFalse(command2.observe().toBlocking().single()); // return from cache #1\n        assertFalse(command3.observe().toBlocking().single()); // return from cache #2\n        Thread.sleep(500); // timeout on command is set to 200ms\n        Boolean value = command4.observe().toBlocking().single(); // return from cache #3\n        assertFalse(value);\n        Future<Boolean> f = command5.observe().toBlocking().toFuture(); // return from cache #4\n        // the bug is that we're getting a null Future back, rather than a Future that returns false\n        assertNotNull(f);\n        assertFalse(f.get());\n\n        assertTrue(command5.isResponseFromFallback());\n        assertTrue(command5.isResponseTimedOut());\n        assertFalse(command5.isFailedExecution());\n        assertFalse(command5.isResponseShortCircuited());\n        assertNotNull(command5.getExecutionException());\n\n        assertCommandExecutionEvents(command1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(command5, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(5);\n    }\n\n    @Test\n    public void testRequestCacheOnTimeoutThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        RequestCacheTimeoutWithoutFallback r1 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            System.out.println(\"r1 value: \" + r1.observe().toBlocking().single());\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r1.isResponseTimedOut());\n            assertNotNull(r1.getExecutionException());\n            // what we want\n        }\n\n        RequestCacheTimeoutWithoutFallback r2 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r2.observe().toBlocking().single();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r2.isResponseTimedOut());\n            assertNotNull(r2.getExecutionException());\n            // what we want\n        }\n\n        RequestCacheTimeoutWithoutFallback r3 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        Future<Boolean> f3 = r3.observe().toBlocking().toFuture();\n        try {\n            f3.get();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            assertTrue(r3.isResponseTimedOut());\n            assertNotNull(r3.getExecutionException());\n            // what we want\n        }\n\n        Thread.sleep(500); // timeout on command is set to 200ms\n\n        RequestCacheTimeoutWithoutFallback r4 = new RequestCacheTimeoutWithoutFallback(circuitBreaker);\n        try {\n            r4.observe().toBlocking().single();\n            // we should have thrown an exception\n            fail(\"expected a timeout\");\n        } catch (HystrixRuntimeException e) {\n            assertTrue(r4.isResponseTimedOut());\n            assertFalse(r4.isResponseFromFallback());\n            assertNotNull(r4.getExecutionException());\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r3, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r4, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    @Test\n    public void testRequestCacheOnThreadRejectionThrowsException() throws Exception {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CountDownLatch completionLatch = new CountDownLatch(1);\n        RequestCacheThreadRejectionWithoutFallback r1 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r1: \" + r1.observe().toBlocking().single());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            e.printStackTrace();\n            assertTrue(r1.isResponseRejected());\n            assertNotNull(r1.getExecutionException());\n            // what we want\n        }\n\n        RequestCacheThreadRejectionWithoutFallback r2 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r2: \" + r2.observe().toBlocking().single());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            //                e.printStackTrace();\n            assertTrue(r2.isResponseRejected());\n            assertNotNull(r2.getExecutionException());\n            // what we want\n        }\n\n        RequestCacheThreadRejectionWithoutFallback r3 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"f3: \" + r3.observe().toBlocking().toFuture().get());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (ExecutionException e) {\n            assertTrue(r3.isResponseRejected());\n            assertTrue(e.getCause() instanceof HystrixRuntimeException);\n            assertNotNull(r3.getExecutionException());\n        }\n\n        // let the command finish (only 1 should actually be blocked on this due to the response cache)\n        completionLatch.countDown();\n\n        // then another after the command has completed\n        RequestCacheThreadRejectionWithoutFallback r4 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch);\n        try {\n            System.out.println(\"r4: \" + r4.observe().toBlocking().single());\n            // we should have thrown an exception\n            fail(\"expected a rejection\");\n        } catch (HystrixRuntimeException e) {\n            //                e.printStackTrace();\n            assertTrue(r4.isResponseRejected());\n            assertFalse(r4.isResponseFromFallback());\n            assertNotNull(r4.getExecutionException());\n            // what we want\n        }\n\n        assertCommandExecutionEvents(r1, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertCommandExecutionEvents(r2, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r3, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertCommandExecutionEvents(r4, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING, HystrixEventType.RESPONSE_FROM_CACHE);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(4);\n    }\n\n    /**\n     * Test that we can do basic execution without a RequestVariable being initialized.\n     */\n    @Test\n    public void testBasicExecutionWorksWithoutRequestVariable() {\n        try {\n            /* force the RequestVariable to not be initialized */\n            HystrixRequestContext.setContextOnCurrentThread(null);\n\n            TestHystrixObservableCommand<Boolean> command = new SuccessfulTestCommand(ExecutionIsolationStrategy.SEMAPHORE);\n            assertEquals(true, command.observe().toBlocking().single());\n\n            TestHystrixObservableCommand<Boolean> command2 = new SuccessfulTestCommand(ExecutionIsolationStrategy.SEMAPHORE);\n            assertEquals(true, command2.observe().toBlocking().toFuture().get());\n\n            // we should be able to execute without a RequestVariable if ...\n            // 1) We don't have a cacheKey\n            // 2) We don't ask for the RequestLog\n            // 3) We don't do collapsing\n\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n            assertNull(command.getExecutionException());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception => \" + e.getMessage());\n        }\n\n        assertNull(HystrixRequestLog.getCurrentRequest());\n    }\n\n    /**\n     * Test that if we try and execute a command with a cacheKey without initializing RequestVariable that it gives an error.\n     */\n    @Test\n    public void testCacheKeyExecutionRequiresRequestVariable() {\n        try {\n            /* force the RequestVariable to not be initialized */\n            HystrixRequestContext.setContextOnCurrentThread(null);\n\n            TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n            SuccessfulCacheableCommand<String> command = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"one\");\n            assertEquals(\"one\", command.observe().toBlocking().single());\n\n            SuccessfulCacheableCommand<String> command2 = new SuccessfulCacheableCommand<String>(circuitBreaker, true, \"two\");\n            assertEquals(\"two\", command2.observe().toBlocking().toFuture().get());\n\n            fail(\"We expect an exception because cacheKey requires RequestVariable.\");\n\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n            assertNull(command.getExecutionException());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Test that a BadRequestException can be synchronously thrown from a semaphore-isolated command and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedBadRequestSyncExceptionObserve() {\n        testBadRequestExceptionObserve(ExecutionIsolationStrategy.SEMAPHORE, KnownHystrixBadRequestFailureTestCommand.SYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that a BadRequestException can be asynchronously thrown from a semaphore-isolated command and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testSemaphoreIsolatedBadRequestAsyncExceptionObserve() {\n        testBadRequestExceptionObserve(ExecutionIsolationStrategy.SEMAPHORE, KnownHystrixBadRequestFailureTestCommand.ASYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that a BadRequestException can be synchronously thrown from a thread-isolated command and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testThreadIsolatedBadRequestSyncExceptionObserve() {\n        testBadRequestExceptionObserve(ExecutionIsolationStrategy.THREAD, KnownHystrixBadRequestFailureTestCommand.SYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that a BadRequestException can be asynchronously thrown from a thread-isolated command and not count towards errors and bypasses fallback.\n     */\n    @Test\n    public void testThreadIsolatedBadRequestAsyncExceptionObserve() {\n        testBadRequestExceptionObserve(ExecutionIsolationStrategy.THREAD, KnownHystrixBadRequestFailureTestCommand.ASYNC_EXCEPTION);\n    }\n\n    private void testBadRequestExceptionObserve(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        KnownHystrixBadRequestFailureTestCommand command1 = new KnownHystrixBadRequestFailureTestCommand(circuitBreaker, isolationStrategy, asyncException);\n        try {\n            command1.observe().toBlocking().single();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (HystrixBadRequestException e) {\n            // success\n            e.printStackTrace();\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We expect a \" + HystrixBadRequestException.class.getSimpleName() + \" but got a \" + e.getClass().getSimpleName());\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertSaneHystrixRequestLog(1);\n        assertNotNull(command1.getExecutionException());\n    }\n\n    /**\n     * Test that synchronous BadRequestException behavior works the same on a cached response for a semaphore-isolated command.\n     */\n    @Test\n    public void testSyncBadRequestExceptionOnResponseFromCacheInSempahore() {\n        testBadRequestExceptionOnResponseFromCache(ExecutionIsolationStrategy.SEMAPHORE, KnownHystrixBadRequestFailureTestCommand.SYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that asynchronous BadRequestException behavior works the same on a cached response for a semaphore-isolated command.\n     */\n    @Test\n    public void testAsyncBadRequestExceptionOnResponseFromCacheInSemaphore() {\n        testBadRequestExceptionOnResponseFromCache(ExecutionIsolationStrategy.SEMAPHORE, KnownHystrixBadRequestFailureTestCommand.ASYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that synchronous BadRequestException behavior works the same on a cached response for a thread-isolated command.\n     */\n    @Test\n    public void testSyncBadRequestExceptionOnResponseFromCacheInThread() {\n        testBadRequestExceptionOnResponseFromCache(ExecutionIsolationStrategy.THREAD, KnownHystrixBadRequestFailureTestCommand.SYNC_EXCEPTION);\n    }\n\n    /**\n     * Test that asynchronous BadRequestException behavior works the same on a cached response for a thread-isolated command.\n     */\n    @Test\n    public void testAsyncBadRequestExceptionOnResponseFromCacheInThread() {\n        testBadRequestExceptionOnResponseFromCache(ExecutionIsolationStrategy.THREAD, KnownHystrixBadRequestFailureTestCommand.ASYNC_EXCEPTION);\n    }\n\n    private void testBadRequestExceptionOnResponseFromCache(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n\n        KnownHystrixBadRequestFailureTestCommand command1 = new KnownHystrixBadRequestFailureTestCommand(circuitBreaker, isolationStrategy, asyncException);\n        // execute once to cache the value\n        try {\n            command1.observe().toBlocking().single();\n        } catch (Throwable e) {\n            // ignore\n        }\n\n        KnownHystrixBadRequestFailureTestCommand command2 = new KnownHystrixBadRequestFailureTestCommand(circuitBreaker, isolationStrategy, asyncException);\n        try {\n            command2.observe().toBlocking().toFuture().get();\n            fail(\"we expect to receive a \" + HystrixBadRequestException.class.getSimpleName());\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n            if (e.getCause() instanceof HystrixBadRequestException) {\n                // success\n            } else {\n                fail(\"We expect a \" + HystrixBadRequestException.class.getSimpleName() + \" but got a \" + e.getClass().getSimpleName());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail();\n        }\n\n        assertCommandExecutionEvents(command1, HystrixEventType.BAD_REQUEST);\n        assertCommandExecutionEvents(command2, HystrixEventType.BAD_REQUEST);\n        assertSaneHystrixRequestLog(2);\n        assertNotNull(command1.getExecutionException());\n        assertNotNull(command2.getExecutionException());\n    }\n\n    /**\n     * Test a checked Exception being thrown\n     */\n    @Test\n    public void testCheckedExceptionViaExecute() {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker);\n        try {\n            command.observe().toBlocking().single();\n            fail(\"we expect to receive a \" + Exception.class.getSimpleName());\n        } catch (Exception e) {\n            assertEquals(\"simulated checked exception message\", e.getCause().getMessage());\n        }\n\n        assertEquals(\"simulated checked exception message\", command.getFailedExecutionException().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a java.lang.Error being thrown\n     *\n     * @throws InterruptedException\n     */\n    @Test\n    public void testCheckedExceptionViaObserve() throws InterruptedException {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker);\n        final AtomicReference<Throwable> t = new AtomicReference<Throwable>();\n        final CountDownLatch latch = new CountDownLatch(1);\n        try {\n            command.observe().subscribe(new Observer<Boolean>() {\n\n                @Override\n                public void onCompleted() {\n                    latch.countDown();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    t.set(e);\n                    latch.countDown();\n                }\n\n                @Override\n                public void onNext(Boolean args) {\n\n                }\n\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"we should not get anything thrown, it should be emitted via the Observer#onError method\");\n        }\n\n        latch.await(1, TimeUnit.SECONDS);\n        assertNotNull(t.get());\n        t.get().printStackTrace();\n\n        assertTrue(t.get() instanceof HystrixRuntimeException);\n        assertEquals(\"simulated checked exception message\", t.get().getCause().getMessage());\n        assertEquals(\"simulated checked exception message\", command.getFailedExecutionException().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    /**\n     * Test a java.lang.Error being thrown\n     *\n     * @throws InterruptedException\n     */\n    @Test\n    public void testErrorThrownViaObserve() throws InterruptedException {\n        TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        CommandWithErrorThrown command = new CommandWithErrorThrown(circuitBreaker, true);\n        final AtomicReference<Throwable> t = new AtomicReference<Throwable>();\n        final CountDownLatch latch = new CountDownLatch(1);\n        try {\n            command.observe().subscribe(new Observer<Boolean>() {\n\n                @Override\n                public void onCompleted() {\n                    latch.countDown();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    t.set(e);\n                    latch.countDown();\n                }\n\n                @Override\n                public void onNext(Boolean args) {\n\n                }\n\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"we should not get anything thrown, it should be emitted via the Observer#onError method\");\n        }\n\n        latch.await(1, TimeUnit.SECONDS);\n        assertNotNull(t.get());\n        t.get().printStackTrace();\n\n        assertTrue(t.get() instanceof HystrixRuntimeException);\n        // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public\n        // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x\n        assertEquals(\"simulated java.lang.Error message\", t.get().getCause().getCause().getMessage());\n        assertEquals(\"simulated java.lang.Error message\", command.getFailedExecutionException().getCause().getMessage());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isFailedExecution());\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertNotNull(command.getExecutionException());\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertFalse(command.isExecutedInThread());\n        assertSaneHystrixRequestLog(1);\n    }\n\n    @Test\n    public void testInterruptObserveOnTimeout() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true);\n\n        // when\n        cmd.observe().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertTrue(cmd.hasBeenInterrupted());\n    }\n\n    @Test\n    public void testInterruptToObservableOnTimeout() throws InterruptedException {\n        // given\n        InterruptibleCommand cmd = new InterruptibleCommand(new TestCircuitBreaker(), true);\n\n        // when\n        cmd.toObservable().subscribe();\n\n        // then\n        Thread.sleep(500);\n        assertTrue(cmd.hasBeenInterrupted());\n    }\n\n\n\n    @Override\n    protected void assertHooksOnSuccess(Func0<TestHystrixObservableCommand<Integer>> ctor, Action1<TestHystrixObservableCommand<Integer>> assertion) {\n        assertBlockingObserve(ctor.call(), assertion, true);\n        assertNonBlockingObserve(ctor.call(), assertion, true);\n    }\n\n    @Override\n    protected void assertHooksOnFailure(Func0<TestHystrixObservableCommand<Integer>> ctor, Action1<TestHystrixObservableCommand<Integer>> assertion) {\n        assertBlockingObserve(ctor.call(), assertion, false);\n        assertNonBlockingObserve(ctor.call(), assertion, false);\n    }\n\n    @Override\n    void assertHooksOnFailure(Func0<TestHystrixObservableCommand<Integer>> ctor, Action1<TestHystrixObservableCommand<Integer>> assertion, boolean failFast) {\n\n    }\n\n    /**\n     *********************** HystrixObservableCommand-specific THREAD-ISOLATED Execution Hook Tests **************************************\n     */\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: EMITx4, SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadMultipleEmitsAndThenSuccess() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.MULTIPLE_EMITS_THEN_SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(4, 0, 1));\n                        assertTrue(hook.executionEventsMatch(4, 0, 1));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionEmit - !onRunSuccess - !onComplete - onEmit - onExecutionSuccess - onThreadComplete - onSuccess - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: EMITx4, FAILURE, FALLBACK_EMITx4, FALLBACK_SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadMultipleEmitsThenErrorThenMultipleFallbackEmitsAndThenFallbackSuccess() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.MULTIPLE_EMITS_THEN_FAILURE, 0, AbstractTestHystrixCommand.FallbackResult.MULTIPLE_EMITS_THEN_SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(8, 0, 1));\n                        assertTrue(hook.executionEventsMatch(4, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(4, 0, 1));\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - \" +\n                                \"onExecutionEmit - !onRunSuccess - !onComplete - onEmit - \" +\n                                \"onExecutionEmit - !onRunSuccess - !onComplete - onEmit - \" +\n                                \"onExecutionEmit - !onRunSuccess - !onComplete - onEmit - \" +\n                                \"onExecutionEmit - !onRunSuccess - !onComplete - onEmit - \" +\n                                \"onExecutionError - !onRunError - onThreadComplete - onFallbackStart - \" +\n                                \"onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - \" +\n                                \"onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - \" +\n                                \"onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - \" +\n                                \"onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - \" +\n                                \"onFallbackSuccess - onSuccess - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: asynchronous HystrixBadRequestException\n     */\n    @Test\n    public void testExecutionHookThreadAsyncBadRequestException() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.ASYNC_BAD_REQUEST);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(HystrixBadRequestException.class, hook.getCommandException().getClass());\n                        assertEquals(HystrixBadRequestException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: async HystrixRuntimeException\n     * Fallback: UnsupportedOperationException\n     */\n    @Test\n    public void testExecutionHookThreadAsyncExceptionNoFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.ASYNC_FAILURE, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 0, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertNull(hook.getFallbackException());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: async HystrixRuntimeException\n     * Fallback: SUCCESS\n     */\n    @Test\n    public void testExecutionHookThreadAsyncExceptionSuccessfulFallback() {\n        assertHooksOnSuccess(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.ASYNC_FAILURE, AbstractTestHystrixCommand.FallbackResult.SUCCESS);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(1, 0, 1));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(1, 0, 1));\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackEmit - !onFallbackSuccess - !onComplete - onEmit - onFallbackSuccess - onSuccess - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: sync HystrixRuntimeException\n     * Fallback: async HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadSyncExceptionAsyncUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.ASYNC_FAILURE);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackError - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: async HystrixRuntimeException\n     * Fallback: sync HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadAsyncExceptionSyncUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.ASYNC_FAILURE, AbstractTestHystrixCommand.FallbackResult.FAILURE);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackError - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: THREAD\n     * Thread Pool fullInteger : NO\n     * Thread Pool Queue fullInteger: NO\n     * Timeout: NO\n     * Execution Result: async HystrixRuntimeException\n     * Fallback: async HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadAsyncExceptionAsyncUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.ASYNC_FAILURE, AbstractTestHystrixCommand.FallbackResult.ASYNC_FAILURE);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onThreadStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onThreadComplete - onFallbackStart - onFallbackError - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     * Short-circuitInteger : YES\n     * Thread/semaphore: THREAD\n     * Fallback: async HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookThreadShortCircuitAsyncUnsuccessfulFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCircuitOpenCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.FallbackResult.ASYNC_FAILURE);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 0, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - onFallbackStart - onFallbackError - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     *********************** END HystrixObservableCommand-specific THREAD-ISOLATED Execution Hook Tests **************************************\n     */\n\n    /**\n     ********************* HystrixObservableCommand-specific SEMAPHORE-ISOLATED Execution Hook Tests ***********************************\n     */\n\n    /**\n     * Short-circuitInteger : NO\n     * Thread/semaphore: SEMAPHORE\n     * Semaphore Permit reachedInteger : NO\n     * Execution Result: HystrixRuntimeException\n     * Fallback: asynchronous HystrixRuntimeException\n     */\n    @Test\n    public void testExecutionHookSemaphoreExceptionUnsuccessfulAsynchronousFallback() {\n        assertHooksOnFailure(\n                new Func0<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public TestHystrixObservableCommand<Integer> call() {\n                        return getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.FAILURE, AbstractTestHystrixCommand.FallbackResult.ASYNC_FAILURE);\n                    }\n                },\n                new Action1<TestHystrixObservableCommand<Integer>>() {\n                    @Override\n                    public void call(TestHystrixObservableCommand<Integer> command) {\n                        TestableExecutionHook hook = command.getBuilder().executionHook;\n                        assertTrue(hook.commandEmissionsMatch(0, 1, 0));\n                        assertTrue(hook.executionEventsMatch(0, 1, 0));\n                        assertTrue(hook.fallbackEventsMatch(0, 1, 0));\n                        assertEquals(RuntimeException.class, hook.getCommandException().getClass());\n                        assertEquals(RuntimeException.class, hook.getExecutionException().getClass());\n                        assertEquals(RuntimeException.class, hook.getFallbackException().getClass());\n                        assertEquals(\"onStart - !onRunStart - onExecutionStart - onExecutionError - !onRunError - onFallbackStart - onFallbackError - onError - \", command.getBuilder().executionHook.executionSequence.toString());\n                    }\n                });\n    }\n\n    /**\n     ********************* END HystrixObservableCommand-specific SEMAPHORE-ISOLATED Execution Hook Tests ***********************************\n     */\n\n    /**\n     * Test a command execution that fails but has a fallback.\n     */\n    @Test\n    public void testExecutionFailureWithFallbackImplementedButDisabled() {\n        TestHystrixObservableCommand<Boolean> commandEnabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), true, true);\n        try {\n            assertEquals(false, commandEnabled.observe().toBlocking().single());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We should have received a response from the fallback.\");\n        }\n\n        TestHystrixObservableCommand<Boolean> commandDisabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), false, true);\n        try {\n            assertEquals(false, commandDisabled.observe().toBlocking().single());\n            fail(\"expect exception thrown\");\n        } catch (Exception e) {\n            // expected\n        }\n\n        assertEquals(\"we failed with a simulated issue\", commandDisabled.getFailedExecutionException().getMessage());\n\n        assertTrue(commandDisabled.isFailedExecution());\n        assertNotNull(commandDisabled.getExecutionException());\n\n        assertCommandExecutionEvents(commandEnabled, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertCommandExecutionEvents(commandDisabled, HystrixEventType.FAILURE);\n        assertEquals(0, commandDisabled.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    /**\n     * Test that we can still use thread isolation if desired.\n     */\n    @Test\n    public void testSynchronousExecutionTimeoutValueViaExecute() {\n        HystrixObservableCommand.Setter properties = HystrixObservableCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestKey\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)\n                        .withExecutionTimeoutInMilliseconds(50));\n\n        System.out.println(\">>>>> Begin: \" + System.currentTimeMillis());\n\n        final AtomicBoolean startedExecution = new AtomicBoolean();\n        HystrixObservableCommand<String> command = new HystrixObservableCommand<String>(properties) {\n            @Override\n            protected Observable<String> construct() {\n\n                return Observable.create(new OnSubscribe<String>() {\n\n                    @Override\n                    public void call(Subscriber<? super String> t1) {\n                        try {\n                            startedExecution.set(true);\n                            Thread.sleep(2000);\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        t1.onNext(\"hello\");\n                        t1.onCompleted();\n                    }\n\n                });\n            }\n\n            @Override\n            protected Observable<String> resumeWithFallback() {\n                if (isResponseTimedOut()) {\n                    return Observable.just(\"timed-out\");\n                } else {\n                    return Observable.just(\"abc\");\n                }\n            }\n        };\n\n        System.out.println(\">>>>> Start: \" + System.currentTimeMillis());\n        String value = command.observe().toBlocking().single();\n        System.out.println(\">>>>> End: \" + System.currentTimeMillis());\n        assertTrue(command.isResponseTimedOut());\n        assertEquals(\"expected fallback value\", \"timed-out\", value);\n\n        // Thread isolated\n        assertTrue(!startedExecution.get() || command.isExecutedInThread());\n        assertNotNull(command.getExecutionException());\n\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    @Test\n    public void testSynchronousExecutionUsingThreadIsolationTimeoutValueViaObserve() {\n        HystrixObservableCommand.Setter properties = HystrixObservableCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestKey\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)\n                        .withExecutionTimeoutInMilliseconds(50));\n\n        final AtomicBoolean startedExecution = new AtomicBoolean();\n        HystrixObservableCommand<String> command = new HystrixObservableCommand<String>(properties) {\n            @Override\n            protected Observable<String> construct() {\n                return Observable.create(new OnSubscribe<String>() {\n\n                    @Override\n                    public void call(Subscriber<? super String> t1) {\n                        startedExecution.set(true);\n                        try {\n                            Thread.sleep(2000);\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        t1.onNext(\"hello\");\n                        t1.onCompleted();\n                    }\n\n                });\n            }\n\n            @Override\n            protected Observable<String> resumeWithFallback() {\n                if (isResponseTimedOut()) {\n                    return Observable.just(\"timed-out\");\n                } else {\n                    return Observable.just(\"abc\");\n                }\n            }\n        };\n\n        String value = command.observe().toBlocking().last();\n        assertTrue(command.isResponseTimedOut());\n        assertEquals(\"expected fallback value\", \"timed-out\", value);\n\n        // Thread isolated\n        assertTrue(!startedExecution.get() || command.isExecutedInThread());\n        assertNotNull(command.getExecutionException());\n\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    @Test\n    public void testAsyncExecutionTimeoutValueViaObserve() {\n        HystrixObservableCommand.Setter properties = HystrixObservableCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestKey\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionTimeoutInMilliseconds(50));\n\n        HystrixObservableCommand<String> command = new HystrixObservableCommand<String>(properties) {\n            @Override\n            protected Observable<String> construct() {\n                return Observable.create(new OnSubscribe<String>() {\n\n                    @Override\n                    public void call(Subscriber<? super String> t1) {\n                        try {\n                            Thread.sleep(2000);\n                        } catch (InterruptedException e) {\n                            System.out.println(\"********** interrupted on timeout\");\n                            e.printStackTrace();\n                        }\n                        // should never reach here\n                        t1.onNext(\"hello\");\n                        t1.onCompleted();\n                    }\n                }).subscribeOn(Schedulers.newThread());\n            }\n\n            @Override\n            protected Observable<String> resumeWithFallback() {\n                if (isResponseTimedOut()) {\n                    return Observable.just(\"timed-out\");\n                } else {\n                    return Observable.just(\"abc\");\n                }\n            }\n        };\n\n        String value = command.observe().toBlocking().last();\n        assertTrue(command.isResponseTimedOut());\n        assertEquals(\"expected fallback value\", \"timed-out\", value);\n\n        // semaphore isolated\n        assertFalse(command.isExecutedInThread());\n        assertNotNull(command.getExecutionException());\n\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n\n        assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    /**\n     * See https://github.com/Netflix/Hystrix/issues/212\n     */\n    @Test\n    public void testObservableTimeoutNoFallbackThreadContext() {\n        TestSubscriber<Integer> ts = new TestSubscriber<Integer>();\n\n        final AtomicReference<Thread> onErrorThread = new AtomicReference<Thread>();\n        final AtomicBoolean isRequestContextInitialized = new AtomicBoolean();\n\n        TestHystrixObservableCommand<Integer> command = getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED, 100);\n        command.toObservable().doOnError(new Action1<Throwable>() {\n\n            @Override\n            public void call(Throwable t1) {\n                System.out.println(\"onError: \" + t1);\n                System.out.println(\"onError Thread: \" + Thread.currentThread());\n                System.out.println(\"ThreadContext in onError: \" + HystrixRequestContext.isCurrentThreadInitialized());\n                onErrorThread.set(Thread.currentThread());\n                isRequestContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n            }\n\n        }).subscribe(ts);\n\n        ts.awaitTerminalEvent();\n\n        assertTrue(isRequestContextInitialized.get());\n        assertTrue(onErrorThread.get().getName().startsWith(\"HystrixTimer\"));\n\n        List<Throwable> errors = ts.getOnErrorEvents();\n        assertEquals(1, errors.size());\n        Throwable e = errors.get(0);\n        if (errors.get(0) instanceof HystrixRuntimeException) {\n            HystrixRuntimeException de = (HystrixRuntimeException) e;\n            assertNotNull(de.getFallbackException());\n            assertTrue(de.getFallbackException() instanceof UnsupportedOperationException);\n            assertNotNull(de.getImplementingClass());\n            assertNotNull(de.getCause());\n            assertTrue(de.getCause() instanceof TimeoutException);\n        } else {\n            fail(\"the exception should be ExecutionException with cause as HystrixRuntimeException\");\n        }\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertFalse(command.isExecutedInThread());\n    }\n\n    /**\n     * See https://github.com/Netflix/Hystrix/issues/212\n     */\n    @Test\n    public void testObservableTimeoutFallbackThreadContext() {\n        TestSubscriber<Object> ts = new TestSubscriber<Object>();\n\n        final AtomicReference<Thread> onErrorThread = new AtomicReference<Thread>();\n        final AtomicBoolean isRequestContextInitialized = new AtomicBoolean();\n\n        TestHystrixObservableCommand<Integer> command = getCommand(ExecutionIsolationStrategy.SEMAPHORE, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 200, AbstractTestHystrixCommand.FallbackResult.SUCCESS, 100);\n        command.toObservable().doOnNext(new Action1<Object>() {\n\n            @Override\n            public void call(Object t1) {\n                System.out.println(\"onNext: \" + t1);\n                System.out.println(\"onNext Thread: \" + Thread.currentThread());\n                System.out.println(\"ThreadContext in onNext: \" + HystrixRequestContext.isCurrentThreadInitialized());\n                onErrorThread.set(Thread.currentThread());\n                isRequestContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n            }\n\n        }).subscribe(ts);\n\n        ts.awaitTerminalEvent();\n\n        System.out.println(\"events: \" + ts.getOnNextEvents());\n\n        assertTrue(isRequestContextInitialized.get());\n        assertTrue(onErrorThread.get().getName().startsWith(\"HystrixTimer\"));\n\n        List<Object> onNexts = ts.getOnNextEvents();\n        assertEquals(1, onNexts.size());\n        //assertFalse( onNexts.get(0));\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isResponseTimedOut());\n        assertNotNull(command.getExecutionException());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        assertFalse(command.isExecutedInThread());\n    }\n\n    @Test\n    public void testRejectedViaSemaphoreIsolation() {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        final ArrayBlockingQueue<Boolean> results = new ArrayBlockingQueue<Boolean>(2);\n\n        final TryableSemaphoreActual semaphore = new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1));\n\n        //used to wait until all commands have started\n        final CountDownLatch startLatch = new CountDownLatch(2);\n\n        // used to signal that all command can finish\n        final CountDownLatch sharedLatch = new CountDownLatch(1);\n\n        final LatchedSemaphoreCommand command1 = new LatchedSemaphoreCommand(circuitBreaker, semaphore, startLatch, sharedLatch);\n        final LatchedSemaphoreCommand command2 = new LatchedSemaphoreCommand(circuitBreaker, semaphore, startLatch, sharedLatch);\n\n        Observable<Boolean> merged = Observable.merge(command1.toObservable(), command2.toObservable())\n                .subscribeOn(Schedulers.newThread());\n\n        final CountDownLatch terminal = new CountDownLatch(1);\n\n        merged.subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(Thread.currentThread().getName() + \" OnCompleted\");\n                terminal.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(Thread.currentThread().getName() + \" OnError : \" + e);\n                terminal.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(Thread.currentThread().getName() + \" OnNext : \" + b);\n                results.offer(b);\n            }\n        });\n\n        try {\n            assertTrue(startLatch.await(1000, TimeUnit.MILLISECONDS));\n            sharedLatch.countDown();\n            assertTrue(terminal.await(1000, TimeUnit.MILLISECONDS));\n        } catch (Throwable ex) {\n            ex.printStackTrace();\n            fail(ex.getMessage());\n        }\n\n        // one thread should have returned values\n        assertEquals(2, results.size());\n        //1 should have gotten the normal value, the other - the fallback\n        assertTrue(results.contains(Boolean.TRUE));\n        assertTrue(results.contains(Boolean.FALSE));\n\n        System.out.println(\"REQ LOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n        assertCommandExecutionEvents(command1, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(2);\n    }\n\n    @Test\n    public void testRejectedViaThreadIsolation() throws InterruptedException {\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        final ArrayBlockingQueue<Boolean> results = new ArrayBlockingQueue<Boolean>(10);\n        final List<Thread> executionThreads = Collections.synchronizedList(new ArrayList<Thread>(20));\n        final List<Thread> responseThreads = Collections.synchronizedList(new ArrayList<Thread>(10));\n\n        final AtomicBoolean exceptionReceived = new AtomicBoolean();\n        final CountDownLatch scheduleLatch = new CountDownLatch(2);\n        final CountDownLatch successLatch = new CountDownLatch(1);\n        final AtomicInteger count = new AtomicInteger();\n        final AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand> command1Ref = new AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand>();\n        final AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand> command2Ref = new AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand>();\n        final AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand> command3Ref = new AtomicReference<TestThreadIsolationWithSemaphoreSetSmallCommand>();\n\n        Runnable r1 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                final boolean shouldExecute = count.incrementAndGet() < 3;\n                try {\n                    executionThreads.add(Thread.currentThread());\n                    TestThreadIsolationWithSemaphoreSetSmallCommand command1 = new TestThreadIsolationWithSemaphoreSetSmallCommand(circuitBreaker, 2, new Action0() {\n\n                        @Override\n                        public void call() {\n                            // make sure it's deterministic and we put 2 threads into the pool before the 3rd is submitted\n                            if (shouldExecute) {\n                                try {\n                                    scheduleLatch.countDown();\n                                    successLatch.await();\n                                } catch (InterruptedException e) {\n                                }\n                            }\n                        }\n\n                    });\n                    command1Ref.set(command1);\n                    results.add(command1.toObservable().map(new Func1<Boolean, Boolean>() {\n\n                        @Override\n                        public Boolean call(Boolean b) {\n                            responseThreads.add(Thread.currentThread());\n                            return b;\n                        }\n\n                    }).doAfterTerminate(new Action0() {\n\n                        @Override\n                        public void call() {\n                            if (!shouldExecute) {\n                                // the final thread that shouldn't execute releases the latch once it has run\n                                // so it is deterministic that the other two fill the thread pool until this one rejects\n                                successLatch.countDown();\n                            }\n                        }\n\n                    }).toBlocking().single());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n        });\n\n        Runnable r2 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                final boolean shouldExecute = count.incrementAndGet() < 3;\n                try {\n                    executionThreads.add(Thread.currentThread());\n                    TestThreadIsolationWithSemaphoreSetSmallCommand command2 = new TestThreadIsolationWithSemaphoreSetSmallCommand(circuitBreaker, 2, new Action0() {\n\n                        @Override\n                        public void call() {\n                            // make sure it's deterministic and we put 2 threads into the pool before the 3rd is submitted\n                            if (shouldExecute) {\n                                try {\n                                    scheduleLatch.countDown();\n                                    successLatch.await();\n                                } catch (InterruptedException e) {\n                                }\n                            }\n                        }\n\n                    });\n                    command2Ref.set(command2);\n                    results.add(command2.toObservable().map(new Func1<Boolean, Boolean>() {\n\n                        @Override\n                        public Boolean call(Boolean b) {\n                            responseThreads.add(Thread.currentThread());\n                            return b;\n                        }\n\n                    }).doAfterTerminate(new Action0() {\n\n                        @Override\n                        public void call() {\n                            if (!shouldExecute) {\n                                // the final thread that shouldn't execute releases the latch once it has run\n                                // so it is deterministic that the other two fill the thread pool until this one rejects\n                                successLatch.countDown();\n                            }\n                        }\n\n                    }).toBlocking().single());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n        });\n\n        Runnable r3 = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() {\n\n            @Override\n            public void run() {\n                final boolean shouldExecute = count.incrementAndGet() < 3;\n                try {\n                    executionThreads.add(Thread.currentThread());\n                    TestThreadIsolationWithSemaphoreSetSmallCommand command3 = new TestThreadIsolationWithSemaphoreSetSmallCommand(circuitBreaker, 2, new Action0() {\n\n                        @Override\n                        public void call() {\n                            // make sure it's deterministic and we put 2 threads into the pool before the 3rd is submitted\n                            if (shouldExecute) {\n                                try {\n                                    scheduleLatch.countDown();\n                                    successLatch.await();\n                                } catch (InterruptedException e) {\n                                }\n                            }\n                        }\n\n                    });\n                    command3Ref.set(command3);\n                    results.add(command3.toObservable().map(new Func1<Boolean, Boolean>() {\n\n                        @Override\n                        public Boolean call(Boolean b) {\n                            responseThreads.add(Thread.currentThread());\n                            return b;\n                        }\n\n                    }).doAfterTerminate(new Action0() {\n\n                        @Override\n                        public void call() {\n                            if (!shouldExecute) {\n                                // the final thread that shouldn't execute releases the latch once it has run\n                                // so it is deterministic that the other two fill the thread pool until this one rejects\n                                successLatch.countDown();\n                            }\n                        }\n\n                    }).toBlocking().single());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    exceptionReceived.set(true);\n                }\n            }\n        });\n\n        // 2 threads, the second should be rejected by the semaphore and return fallback\n        Thread t1 = new Thread(r1);\n        Thread t2 = new Thread(r2);\n        Thread t3 = new Thread(r3);\n\n        t1.start();\n        t2.start();\n        // wait for the previous 2 thread to be running before starting otherwise it can race\n        scheduleLatch.await(500, TimeUnit.MILLISECONDS);\n        t3.start();\n        try {\n            t1.join();\n            t2.join();\n            t3.join();\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"failed waiting on threads\");\n        }\n\n        // we should have 2 of the 3 return results\n        assertEquals(2, results.size());\n        // the other thread should have thrown an Exception\n        assertTrue(exceptionReceived.get());\n\n        assertCommandExecutionEvents(command1Ref.get(), HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command2Ref.get(), HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertCommandExecutionEvents(command3Ref.get(), HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, circuitBreaker.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(3);\n    }\n\n    /* ******************************************************************************************************** */\n    /* *************************************** Request Context Testing Below ********************************** */\n    /* ******************************************************************************************************** */\n\n    private RequestContextTestResults testRequestContextOnSuccess(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder()\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onNext(true);\n                        s.onCompleted();\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(1, results.ts.getOnNextEvents().size());\n        assertTrue(results.ts.getOnNextEvents().get(0));\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertTrue(command.isSuccessfulExecution());\n\n        assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnGracefulFailure(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(circuitBreaker)\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onError(new RuntimeException(\"graceful onError\"));\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(1, results.ts.getOnErrorEvents().size());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isFailedExecution());\n\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnBadFailure(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        throw new RuntimeException(\"bad onError\");\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(1, results.ts.getOnErrorEvents().size());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isFailedExecution());\n\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        s.onError(new RuntimeException(\"onError\"));\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n            @Override\n            protected Observable<Boolean> resumeWithFallback() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onNext(false);\n                        s.onCompleted();\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(0, results.ts.getOnErrorEvents().size());\n        assertEquals(1, results.ts.getOnNextEvents().size());\n        assertEquals(false, results.ts.getOnNextEvents().get(0));\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isFailedExecution());\n\n        assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                        .withExecutionIsolationStrategy(isolation)\n                        .withExecutionIsolationSemaphoreMaxConcurrentRequests(0))\n                .setThreadPool(new HystrixThreadPool() {\n\n                    @Override\n                    public ThreadPoolExecutor getExecutor() {\n                        return null;\n                    }\n\n                    @Override\n                    public void markThreadExecution() {\n\n                    }\n\n                    @Override\n                    public void markThreadCompletion() {\n\n                    }\n\n                    @Override\n                    public void markThreadRejection() {\n\n                    }\n\n                    @Override\n                    public boolean isQueueSpaceAvailable() {\n                        // always return false so we reject everything\n                        return false;\n                    }\n\n                    @Override\n                    public Scheduler getScheduler() {\n                        return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);\n                    }\n\n                    @Override\n                    public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n                        return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n                    }\n\n                })) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        s.onError(new RuntimeException(\"onError\"));\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n            @Override\n            protected Observable<Boolean> resumeWithFallback() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onNext(false);\n                        s.onCompleted();\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(0, results.ts.getOnErrorEvents().size());\n        assertEquals(1, results.ts.getOnNextEvents().size());\n        assertEquals(false, results.ts.getOnNextEvents().get(0));\n\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isResponseRejected());\n\n        if (isolation == ExecutionIsolationStrategy.SEMAPHORE) {\n            assertCommandExecutionEvents(command, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        } else {\n            assertCommandExecutionEvents(command, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        }\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                        .withExecutionIsolationStrategy(isolation))\n                .setCircuitBreaker(new TestCircuitBreaker().setForceShortCircuit(true))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        s.onError(new RuntimeException(\"onError\"));\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n            @Override\n            protected Observable<Boolean> resumeWithFallback() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onNext(false);\n                        s.onCompleted();\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(0, results.ts.getOnErrorEvents().size());\n        assertEquals(1, results.ts.getOnNextEvents().size());\n        assertEquals(false, results.ts.getOnNextEvents().get(0));\n\n        assertTrue(command.getExecutionTimeInMilliseconds() == -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isResponseShortCircuited());\n\n        assertCommandExecutionEvents(command, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnTimeout(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionTimeoutInMilliseconds(50))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        try {\n                            Thread.sleep(500);\n                        } catch (InterruptedException e) {\n                            // ignore the interrupted exception\n                        }\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Run => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(1, results.ts.getOnErrorEvents().size());\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isResponseTimedOut());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_MISSING);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private RequestContextTestResults testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {\n        final RequestContextTestResults results = new RequestContextTestResults();\n        TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker())\n                .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionTimeoutInMilliseconds(50))) {\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        try {\n                            Thread.sleep(500);\n                        } catch (InterruptedException e) {\n                            // ignore the interrupted exception\n                        }\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n            @Override\n            protected Observable<Boolean> resumeWithFallback() {\n                return Observable.create(new OnSubscribe<Boolean>() {\n\n                    @Override\n                    public void call(Subscriber<? super Boolean> s) {\n                        results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                        results.originThread.set(Thread.currentThread());\n                        s.onNext(false);\n                        s.onCompleted();\n                    }\n\n                }).subscribeOn(userScheduler);\n            }\n\n        };\n\n        results.command = command;\n\n        command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {\n\n            @Override\n            public void call(Notification<? super Boolean> n) {\n                System.out.println(\"timeoutWithFallback notification: \" + n + \"   \" + Thread.currentThread());\n                results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());\n                results.observeOnThread.set(Thread.currentThread());\n            }\n\n        }).subscribe(results.ts);\n        results.ts.awaitTerminalEvent();\n\n        System.out.println(\"Fallback => Initialized: \" + results.isContextInitialized.get() + \"  Thread: \" + results.originThread.get());\n        System.out.println(\"Observed => Initialized: \" + results.isContextInitializedObserveOn.get() + \"  Thread: \" + results.observeOnThread.get());\n\n        assertEquals(1, results.ts.getOnNextEvents().size());\n        assertEquals(false, results.ts.getOnNextEvents().get(0));\n\n        assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n        assertFalse(command.isSuccessfulExecution());\n        assertTrue(command.isResponseTimedOut());\n\n        assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n        assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n        assertSaneHystrixRequestLog(1);\n        return results;\n    }\n\n    private final class RequestContextTestResults {\n        volatile TestHystrixObservableCommand<Boolean> command;\n        final AtomicReference<Thread> originThread = new AtomicReference<Thread>();\n        final AtomicBoolean isContextInitialized = new AtomicBoolean();\n        TestSubscriber<Boolean> ts = new TestSubscriber<Boolean>();\n        final AtomicBoolean isContextInitializedObserveOn = new AtomicBoolean();\n        final AtomicReference<Thread> observeOnThread = new AtomicReference<Thread>();\n    }\n\n    /* *************************************** testSuccessfulRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testSuccessfulRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testSuccessfulRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testSuccessfulRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testSuccessfulRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"hystrix-OWNER_ONE\")); // thread isolated on a HystrixThreadPool\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"hystrix-OWNER_ONE\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testSuccessfulRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testSuccessfulRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testGracefulFailureRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"hystrix-OWNER_ONE\")); // thread isolated on a HystrixThreadPool\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"hystrix-OWNER_ONE\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testGracefulFailureRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testBadFailureRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testBadFailureRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testBadFailureRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testBadFailureRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testBadFailureRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"hystrix-OWNER_ONE\")); // thread isolated on a HystrixThreadPool\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"hystrix-OWNER_ONE\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testBadFailureRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testBadFailureRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testFailureWithFallbackRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"hystrix-OWNER_ONE\")); // thread isolated on a HystrixThreadPool\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"hystrix-OWNER_ONE\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testFailureWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testRejectionWithFallbackRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // fallback is performed by the calling thread\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        System.out.println(\"results.observeOnThread.get(): \" + results.observeOnThread.get() + \"  \" + Thread.currentThread());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // rejected so we stay on calling thread\n\n        // thread isolated, but rejected, so this is false\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\"));\n\n        // thread isolated, but rejected, so this is false\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testRejectionWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler for getFallback\n\n        // thread isolated, but rejected, so this is false\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testShortCircuitedWithFallbackRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation]\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // fallback is performed by the calling thread\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // rejected so we stay on calling thread\n\n        // thread isolated ... but rejected so not executed in a thread\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler from getFallback\n\n        // thread isolated ... but rejected so not executed in a thread\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler from getFallback\n\n        // thread isolated ... but rejected so not executed in a thread\n        assertFalse(results.command.isExecutedInThread());\n    }\n\n    /* *************************************** testTimeoutRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this.\n     */\n    @Test\n    public void testTimeoutRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"HystrixTimer\")); // timeout schedules on HystrixTimer since the original thread was timed out\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testTimeoutRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"HystrixTimer\")); // timeout schedules on HystrixTimer since the original thread was timed out\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testTimeoutRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"HystrixTimer\")); // timeout schedules on HystrixTimer since the original thread was timed out\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n\n    /* *************************************** testTimeoutWithFallbackRequestContext *********************************** */\n\n    /**\n     * Synchronous Observable and semaphore isolation.\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"HystrixTimer\")); // timeout uses HystrixTimer thread\n        //(this use case is a little odd as it should generally not be the case that we are \"timing out\" a synchronous observable on semaphore isolation)\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"HystrixTimer\")); // timeout uses HystrixTimer thread\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // semaphore isolated\n        assertFalse(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [HystrixTimer]\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate());\n\n        assertTrue(results.isContextInitialized.get());\n        assertTrue(results.originThread.get().getName().startsWith(\"HystrixTimer\")); // timeout uses HystrixTimer thread for fallback\n\n        assertTrue(results.isContextInitializedObserveOn.get());\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"HystrixTimer\")); // fallback uses the timeout thread\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls.\n     *\n     * NOTE: RequestContext will NOT exist on that thread.\n     *\n     * An async Observable running on its own thread will not have access to the request context unless the user manages the context.\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread());\n\n        assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n\n        HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Async Observable and semaphore isolation WITH functioning RequestContext\n     *\n     * Use HystrixContextScheduler to make the user provided scheduler capture context.\n     */\n    @Test\n    public void testTimeoutWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() {\n        RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread()));\n\n        assertTrue(results.isContextInitialized.get()); // the user scheduler captures context\n        assertTrue(results.originThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context\n        assertTrue(results.observeOnThread.get().getName().startsWith(\"RxNewThread\")); // the user provided thread/scheduler\n\n        // thread isolated\n        assertTrue(results.command.isExecutedInThread());\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ex) {\n\n        }\n        //HystrixCircuitBreaker.Factory.reset();\n    }\n\n    /**\n     * Test support of multiple onNext events.\n     */\n    @Test\n    public void testExecutionSuccessWithMultipleEvents() {\n        try {\n            TestCommandWithMultipleValues command = new TestCommandWithMultipleValues();\n            assertEquals(Arrays.asList(true, false, true), command.observe().toList().toBlocking().single());\n\n            assertEquals(null, command.getFailedExecutionException());\n            assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n            assertTrue(command.isSuccessfulExecution());\n            assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.SUCCESS);\n            assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    /**\n     * Test behavior when some onNext are received and then a failure.\n     */\n    @Test\n    public void testExecutionPartialSuccess() {\n        try {\n            TestPartialSuccess command = new TestPartialSuccess();\n            TestSubscriber<Integer> ts = new TestSubscriber<Integer>();\n            command.toObservable().subscribe(ts);\n            ts.awaitTerminalEvent();\n            ts.assertReceivedOnNext(Arrays.asList(1, 2, 3));\n            assertEquals(1, ts.getOnErrorEvents().size());\n\n            assertFalse(command.isSuccessfulExecution());\n            assertTrue(command.isFailedExecution());\n\n            // we will have an exception\n            assertNotNull(command.getFailedExecutionException());\n\n            assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n            assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);\n            assertSaneHystrixRequestLog(1);\n            assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    /**\n     * Test behavior when some onNext are received and then a failure.\n     */\n    @Test\n    public void testExecutionPartialSuccessWithFallback() {\n        try {\n            TestPartialSuccessWithFallback command = new TestPartialSuccessWithFallback();\n            TestSubscriber<Boolean> ts = new TestSubscriber<Boolean>();\n            command.toObservable().subscribe(ts);\n            ts.awaitTerminalEvent();\n            ts.assertReceivedOnNext(Arrays.asList(false, true, false, true, false, true, false));\n            ts.assertNoErrors();\n\n            assertFalse(command.isSuccessfulExecution());\n            assertTrue(command.isFailedExecution());\n\n            assertNotNull(command.getFailedExecutionException());\n            assertTrue(command.getExecutionTimeInMilliseconds() > -1);\n            assertCommandExecutionEvents(command, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.FAILURE,\n                    HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);\n            assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());\n            assertSaneHystrixRequestLog(1);\n            // semaphore isolated\n            assertFalse(command.isExecutedInThread());\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"We received an exception.\");\n        }\n    }\n\n    @Test\n    public void testEarlyUnsubscribeDuringExecutionViaToObservable() {\n        class AsyncCommand extends HystrixObservableCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.defer(new Func0<Observable<Boolean>>() {\n                    @Override\n                    public Observable<Boolean> call() {\n                        try {\n                            Thread.sleep(100);\n                            return Observable.just(true);\n                        } catch (InterruptedException ex) {\n                            return Observable.error(ex);\n                        }\n                    }\n                }).subscribeOn(Schedulers.io());\n            }\n        }\n\n        HystrixObservableCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.toObservable();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(cmd.isExecutionComplete());\n            assertFalse(cmd.isExecutedInThread());\n            System.out.println(\"EventCounts : \" + cmd.getEventCounts());\n            System.out.println(\"Execution Time : \" + cmd.getExecutionTimeInMilliseconds());\n            System.out.println(\"Is Successful : \" + cmd.isSuccessfulExecution());\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Test\n    public void testEarlyUnsubscribeDuringExecutionViaObserve() {\n        class AsyncCommand extends HystrixObservableCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.defer(new Func0<Observable<Boolean>>() {\n                    @Override\n                    public Observable<Boolean> call() {\n                        try {\n                            Thread.sleep(100);\n                            return Observable.just(true);\n                        } catch (InterruptedException ex) {\n                            return Observable.error(ex);\n                        }\n                    }\n                }).subscribeOn(Schedulers.io());\n            }\n        }\n\n        HystrixObservableCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.observe();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(cmd.isExecutionComplete());\n            assertFalse(cmd.isExecutedInThread());\n            System.out.println(\"EventCounts : \" + cmd.getEventCounts());\n            System.out.println(\"Execution Time : \" + cmd.getExecutionTimeInMilliseconds());\n            System.out.println(\"Is Successful : \" + cmd.isSuccessfulExecution());\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n\n    @Test\n    public void testEarlyUnsubscribeDuringFallback() {\n        class AsyncCommand extends HystrixObservableCommand<Boolean> {\n\n            public AsyncCommand() {\n                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ASYNC\")));\n            }\n\n            @Override\n            protected Observable<Boolean> construct() {\n                return Observable.error(new RuntimeException(\"construct failure\"));\n            }\n\n            @Override\n            protected Observable<Boolean> resumeWithFallback() {\n                return Observable.defer(new Func0<Observable<Boolean>>() {\n                    @Override\n                    public Observable<Boolean> call() {\n                        try {\n                            Thread.sleep(100);\n                            return Observable.just(false);\n                        } catch (InterruptedException ex) {\n                            return Observable.error(ex);\n                        }\n                    }\n                }).subscribeOn(Schedulers.io());\n            }\n        }\n\n        HystrixObservableCommand<Boolean> cmd = new AsyncCommand();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable<Boolean> o = cmd.toObservable();\n        Subscription s = o.\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(\"OnUnsubscribe\");\n                        latch.countDown();\n                    }\n                }).\n                subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(\"OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(\"OnError : \" + e);\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        System.out.println(\"OnNext : \" + b);\n                    }\n                });\n\n        try {\n            Thread.sleep(10); //give fallback a chance to fire\n            s.unsubscribe();\n            assertTrue(latch.await(200, TimeUnit.MILLISECONDS));\n            assertEquals(\"Number of execution semaphores in use\", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());\n            assertEquals(\"Number of fallback semaphores in use\", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());\n            assertFalse(cmd.isExecutionComplete());\n            assertFalse(cmd.isExecutedInThread());\n        } catch (InterruptedException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n    /* private HystrixCommand class implementations for unit testing */\n    /* ******************************************************************************** */\n    /* ******************************************************************************** */\n\n    static AtomicInteger uniqueNameCounter = new AtomicInteger(0);\n\n    @Override\n    TestHystrixObservableCommand<Integer> getCommand(ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, AbstractCommand.TryableSemaphore executionSemaphore, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"FlexibleObservable-\" + uniqueNameCounter.getAndIncrement());\n        return FlexibleTestHystrixObservableCommand.from(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    @Override\n    TestHystrixObservableCommand<Integer> getCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, AbstractCommand.TryableSemaphore executionSemaphore, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n        return FlexibleTestHystrixObservableCommand.from(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n    }\n\n    private static class FlexibleTestHystrixObservableCommand  {\n        public static Integer EXECUTE_VALUE = 1;\n        public static Integer FALLBACK_VALUE = 11;\n\n        public static AbstractFlexibleTestHystrixObservableCommand from(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, AbstractTestHystrixCommand.FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, AbstractTestHystrixCommand.CacheEnabled cacheEnabled, Object value, AbstractCommand.TryableSemaphore executionSemaphore, AbstractCommand.TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            if (fallbackResult.equals(AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED)) {\n                return new FlexibleTestHystrixObservableCommandNoFallback(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            } else {\n                return new FlexibleTestHystrixObservableCommandWithFallback(commandKey, isolationStrategy, executionResult, executionLatency, fallbackResult, fallbackLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            }\n        }\n    }\n\n    private static class AbstractFlexibleTestHystrixObservableCommand extends TestHystrixObservableCommand<Integer> {\n        private final AbstractTestHystrixCommand.ExecutionResult executionResult;\n        private final int executionLatency;\n        private final CacheEnabled cacheEnabled;\n        private final Object value;\n\n        public AbstractFlexibleTestHystrixObservableCommand(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(testPropsBuilder(circuitBreaker)\n                    .setCommandKey(commandKey)\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setThreadPool(threadPool)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(isolationStrategy)\n                            .withExecutionTimeoutInMilliseconds(timeout)\n                            .withCircuitBreakerEnabled(!circuitBreakerDisabled))\n                    .setExecutionSemaphore(executionSemaphore)\n                    .setFallbackSemaphore(fallbackSemaphore));\n            this.executionResult = executionResult;\n            this.executionLatency = executionLatency;\n            this.cacheEnabled = cacheEnabled;\n            this.value = value;\n        }\n\n        @Override\n        protected Observable<Integer> construct() {\n            if (executionResult == AbstractTestHystrixCommand.ExecutionResult.FAILURE) {\n                addLatency(executionLatency);\n                throw new RuntimeException(\"Execution Sync Failure for TestHystrixObservableCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.HYSTRIX_FAILURE) {\n                addLatency(executionLatency);\n                throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION, AbstractFlexibleTestHystrixObservableCommand.class, \"Execution Hystrix Failure for TestHystrixObservableCommand\", new RuntimeException(\"Execution Failure for TestHystrixObservableCommand\"), new RuntimeException(\"Fallback Failure for TestHystrixObservableCommand\"));\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.NOT_WRAPPED_FAILURE) {\n                addLatency(executionLatency);\n                throw new NotWrappedByHystrixTestRuntimeException();\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.RECOVERABLE_ERROR) {\n                addLatency(executionLatency);\n                throw new java.lang.Error(\"Execution Sync Error for TestHystrixObservableCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.UNRECOVERABLE_ERROR) {\n                addLatency(executionLatency);\n                throw new OutOfMemoryError(\"Execution Sync OOME for TestHystrixObservableCommand\");\n            } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.BAD_REQUEST) {\n                addLatency(executionLatency);\n                throw new HystrixBadRequestException(\"Execution Bad Request Exception for TestHystrixObservableCommand\");\n            }\n            return Observable.create(new OnSubscribe<Integer>() {\n                @Override\n                public void call(Subscriber<? super Integer> subscriber) {\n                    System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" construct() method has been subscribed to\");\n                    addLatency(executionLatency);\n                    if (executionResult == AbstractTestHystrixCommand.ExecutionResult.SUCCESS) {\n                        subscriber.onNext(1);\n                        subscriber.onCompleted();\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.MULTIPLE_EMITS_THEN_SUCCESS) {\n                        subscriber.onNext(2);\n                        subscriber.onNext(3);\n                        subscriber.onNext(4);\n                        subscriber.onNext(5);\n                        subscriber.onCompleted();\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.MULTIPLE_EMITS_THEN_FAILURE) {\n                        subscriber.onNext(6);\n                        subscriber.onNext(7);\n                        subscriber.onNext(8);\n                        subscriber.onNext(9);\n                        subscriber.onError(new RuntimeException(\"Execution Async Failure For TestHystrixObservableCommand after 4 emits\"));\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.ASYNC_FAILURE) {\n                        subscriber.onError(new RuntimeException(\"Execution Async Failure for TestHystrixObservableCommand after 0 emits\"));\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.ASYNC_HYSTRIX_FAILURE) {\n                        subscriber.onError(new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION, AbstractFlexibleTestHystrixObservableCommand.class, \"Execution Hystrix Failure for TestHystrixObservableCommand\", new RuntimeException(\"Execution Failure for TestHystrixObservableCommand\"), new RuntimeException(\"Fallback Failure for TestHystrixObservableCommand\")));\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.ASYNC_RECOVERABLE_ERROR) {\n                        subscriber.onError(new java.lang.Error(\"Execution Async Error for TestHystrixObservableCommand\"));\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.ASYNC_UNRECOVERABLE_ERROR) {\n                        subscriber.onError(new OutOfMemoryError(\"Execution Async OOME for TestHystrixObservableCommand\"));\n                    } else if (executionResult == AbstractTestHystrixCommand.ExecutionResult.ASYNC_BAD_REQUEST) {\n                        subscriber.onError(new HystrixBadRequestException(\"Execution Async Bad Request Exception for TestHystrixObservableCommand\"));\n                    } else {\n                        subscriber.onError(new RuntimeException(\"You passed in a executionResult enum that can't be represented in HystrixObservableCommand: \" + executionResult));\n                    }\n                }\n            });\n        }\n\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled == CacheEnabled.YES)\n                return value.toString();\n            else\n                return null;\n        }\n\n        protected void addLatency(int latency) {\n            if (latency > 0) {\n                try {\n                    System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" About to sleep for : \" + latency);\n                    Thread.sleep(latency);\n                    System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Woke up from sleep!\");\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                    // ignore and sleep some more to simulate a dependency that doesn't obey interrupts\n                    try {\n                        Thread.sleep(latency);\n                    } catch (Exception e2) {\n                        // ignore\n                    }\n                    System.out.println(\"after interruption with extra sleep\");\n                }\n            }\n        }\n    }\n\n    private static class FlexibleTestHystrixObservableCommandWithFallback extends AbstractFlexibleTestHystrixObservableCommand {\n        private final AbstractTestHystrixCommand.FallbackResult fallbackResult;\n        private final int fallbackLatency;\n\n        public FlexibleTestHystrixObservableCommandWithFallback(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, FallbackResult fallbackResult, int fallbackLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n            this.fallbackResult = fallbackResult;\n            this.fallbackLatency = fallbackLatency;\n        }\n\n        @Override\n        protected Observable<Integer> resumeWithFallback() {\n            if (fallbackResult == AbstractTestHystrixCommand.FallbackResult.FAILURE) {\n                addLatency(fallbackLatency);\n                throw new RuntimeException(\"Fallback Sync Failure for TestHystrixCommand\");\n            } else if (fallbackResult == FallbackResult.UNIMPLEMENTED) {\n                addLatency(fallbackLatency);\n                return super.resumeWithFallback();\n            }\n            return Observable.create(new OnSubscribe<Integer>() {\n                @Override\n                public void call(Subscriber<? super Integer> subscriber) {\n                    addLatency(fallbackLatency);\n                    if (fallbackResult == AbstractTestHystrixCommand.FallbackResult.SUCCESS) {\n                        subscriber.onNext(11);\n                        subscriber.onCompleted();\n                    } else if (fallbackResult == FallbackResult.MULTIPLE_EMITS_THEN_SUCCESS) {\n                        subscriber.onNext(12);\n                        subscriber.onNext(13);\n                        subscriber.onNext(14);\n                        subscriber.onNext(15);\n                        subscriber.onCompleted();\n                    } else if (fallbackResult == FallbackResult.MULTIPLE_EMITS_THEN_FAILURE) {\n                        subscriber.onNext(16);\n                        subscriber.onNext(17);\n                        subscriber.onNext(18);\n                        subscriber.onNext(19);\n                        subscriber.onError(new RuntimeException(\"Fallback Async Failure For TestHystrixObservableCommand after 4 emits\"));\n                    } else if (fallbackResult == AbstractTestHystrixCommand.FallbackResult.ASYNC_FAILURE) {\n                        subscriber.onError(new RuntimeException(\"Fallback Async Failure for TestHystrixCommand after 0 fallback emits\"));\n                    } else {\n                        subscriber.onError(new RuntimeException(\"You passed in a fallbackResult enum that can't be represented in HystrixObservableCommand: \" + fallbackResult));\n                    }\n                }\n            });\n        }\n    }\n\n    private static class FlexibleTestHystrixObservableCommandNoFallback extends AbstractFlexibleTestHystrixObservableCommand {\n        public FlexibleTestHystrixObservableCommandNoFallback(HystrixCommandKey commandKey, ExecutionIsolationStrategy isolationStrategy, AbstractTestHystrixCommand.ExecutionResult executionResult, int executionLatency, TestCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, int timeout, CacheEnabled cacheEnabled, Object value, TryableSemaphore executionSemaphore, TryableSemaphore fallbackSemaphore, boolean circuitBreakerDisabled) {\n            super(commandKey, isolationStrategy, executionResult, executionLatency, circuitBreaker, threadPool, timeout, cacheEnabled, value, executionSemaphore, fallbackSemaphore, circuitBreakerDisabled);\n        }\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class SuccessfulTestCommand extends TestHystrixObservableCommand<Boolean> {\n\n        public SuccessfulTestCommand(ExecutionIsolationStrategy isolationStrategy) {\n            this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy));\n        }\n\n        public SuccessfulTestCommand(HystrixCommandProperties.Setter properties) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(properties));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.just(true).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class TestCommandWithMultipleValues extends TestHystrixObservableCommand<Boolean> {\n\n        public TestCommandWithMultipleValues() {\n            this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        public TestCommandWithMultipleValues(HystrixCommandProperties.Setter properties) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(properties));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.just(true, false, true).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    private static class TestPartialSuccess extends TestHystrixObservableCommand<Integer> {\n\n        TestPartialSuccess() {\n            super(TestHystrixObservableCommand.testPropsBuilder());\n        }\n\n        @Override\n        protected Observable<Integer> construct() {\n            return Observable.just(1, 2, 3)\n                    .concatWith(Observable.<Integer> error(new RuntimeException(\"forced error\")))\n                    .subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    private static class TestPartialSuccessWithFallback extends TestHystrixObservableCommand<Boolean> {\n\n        TestPartialSuccessWithFallback() {\n            super(TestHystrixObservableCommand.testPropsBuilder());\n        }\n\n        public TestPartialSuccessWithFallback(ExecutionIsolationStrategy isolationStrategy) {\n            this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy));\n        }\n\n        public TestPartialSuccessWithFallback(HystrixCommandProperties.Setter properties) {\n            super(testPropsBuilder().setCommandPropertiesDefaults(properties));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.just(false, true, false)\n                    .concatWith(Observable.<Boolean>error(new RuntimeException(\"forced error\")))\n                    .subscribeOn(Schedulers.computation());\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            return Observable.just(true, false, true, false);\n        }\n\n    }\n\n\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class DynamicOwnerTestCommand extends TestHystrixObservableCommand<Boolean> {\n\n        public DynamicOwnerTestCommand(HystrixCommandGroupKey owner) {\n            super(testPropsBuilder().setOwner(owner));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"successfully executed\");\n            return Observable.just(true).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    /**\n     * Successful execution - no fallback implementation.\n     */\n    private static class DynamicOwnerAndKeyTestCommand extends TestHystrixObservableCommand<Boolean> {\n\n        public DynamicOwnerAndKeyTestCommand(HystrixCommandGroupKey owner, HystrixCommandKey key) {\n            super(testPropsBuilder().setOwner(owner).setCommandKey(key).setCircuitBreaker(null).setMetrics(null));\n            // we specifically are NOT passing in a circuit breaker here so we test that it creates a new one correctly based on the dynamic key\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"successfully executed\");\n            return Observable.just(true).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    /**\n     * Failed execution with unknown exception (not HystrixException) - no fallback implementation.\n     */\n    private static class UnknownFailureTestCommandWithoutFallback extends TestHystrixObservableCommand<Boolean> {\n\n        private final boolean asyncException;\n\n        private UnknownFailureTestCommandWithoutFallback(ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n            super(testPropsBuilder(isolationStrategy, new TestCircuitBreaker()));\n            this.asyncException = asyncException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"*** simulated failed execution ***\");\n            RuntimeException ex = new RuntimeException(\"we failed with an unknown issue\");\n            if (asyncException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n    }\n\n    /**\n     * Failed execution with known exception (HystrixException) - no fallback implementation.\n     */\n    private static class KnownFailureTestCommandWithoutFallback extends TestHystrixObservableCommand<Boolean> {\n\n        final boolean asyncException;\n\n        private KnownFailureTestCommandWithoutFallback(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n            super(testPropsBuilder(isolationStrategy, circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.asyncException = asyncException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"*** simulated failed execution ***\");\n            RuntimeException ex = new RuntimeException(\"we failed with a simulated issue\");\n            if (asyncException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n    }\n\n    /**\n     * Failed execution - fallback implementation successfully returns value.\n     */\n    private static class KnownFailureTestCommandWithFallback extends TestHystrixObservableCommand<Boolean> {\n\n        private final boolean asyncException;\n\n        public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n            super(testPropsBuilder(isolationStrategy, circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.asyncException = asyncException;\n        }\n\n        public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker, boolean fallbackEnabled, boolean asyncException) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withFallbackEnabled(fallbackEnabled).withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));\n            this.asyncException = asyncException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"*** simulated failed execution ***\");\n            RuntimeException ex = new RuntimeException(\"we failed with a simulated issue\");\n            if (asyncException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            return Observable.just(false).subscribeOn(Schedulers.computation());\n        }\n    }\n\n    /**\n     * Failed execution with {@link HystrixBadRequestException}\n     */\n    private static class KnownHystrixBadRequestFailureTestCommand extends TestHystrixObservableCommand<Boolean> {\n\n        public final static boolean ASYNC_EXCEPTION = true;\n        public final static boolean SYNC_EXCEPTION = false;\n\n        private final boolean asyncException;\n\n        public KnownHystrixBadRequestFailureTestCommand(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationStrategy, boolean asyncException) {\n            super(testPropsBuilder(isolationStrategy, circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.asyncException = asyncException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"*** simulated failed with HystrixBadRequestException  ***\");\n            RuntimeException ex = new HystrixBadRequestException(\"we failed with a simulated issue\");\n            if (asyncException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n    }\n\n    /**\n     * Failed execution - fallback implementation throws exception.\n     */\n    private static class KnownFailureTestCommandWithFallbackFailure extends TestHystrixObservableCommand<Boolean> {\n\n        private final boolean asyncConstructException;\n        private final boolean asyncFallbackException;\n\n        private KnownFailureTestCommandWithFallbackFailure(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationStrategy, boolean asyncConstructException, boolean asyncFallbackException) {\n            super(testPropsBuilder(isolationStrategy, circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.asyncConstructException = asyncConstructException;\n            this.asyncFallbackException = asyncFallbackException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            RuntimeException ex = new RuntimeException(\"we failed with a simulated issue\");\n            System.out.println(\"*** simulated failed execution ***\");\n            if (asyncConstructException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            RuntimeException ex = new RuntimeException(\"failed while getting fallback\");\n            if (asyncFallbackException) {\n                return Observable.error(ex);\n            } else {\n                throw ex;\n            }\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCommand<T> extends TestHystrixObservableCommand<T> {\n\n        private final boolean cacheEnabled;\n        private volatile boolean executed = false;\n        private final T value;\n\n        public SuccessfulCacheableCommand(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, T value) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)));\n            this.value = value;\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        protected Observable<T> construct() {\n            executed = true;\n            System.out.println(\"successfully executed\");\n            return Observable.just(value).subscribeOn(Schedulers.computation());\n        }\n\n        public boolean isCommandRunningInThread() {\n            return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD);\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return value.toString();\n            else\n                return null;\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching.\n     */\n    private static class SuccessfulCacheableCommandViaSemaphore extends TestHystrixObservableCommand<String> {\n\n        private final boolean cacheEnabled;\n        private volatile boolean executed = false;\n        private final String value;\n\n        public SuccessfulCacheableCommandViaSemaphore(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, String value) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));\n            this.value = value;\n            this.cacheEnabled = cacheEnabled;\n        }\n\n        @Override\n        protected Observable<String> construct() {\n            executed = true;\n            System.out.println(\"successfully executed\");\n            return Observable.just(value).subscribeOn(Schedulers.computation());\n        }\n\n        public boolean isCommandRunningInThread() {\n            return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD);\n        }\n\n        @Override\n        public String getCacheKey() {\n            if (cacheEnabled)\n                return value;\n            else\n                return null;\n        }\n    }\n\n    /**\n     * A Command implementation that supports caching and execution takes a while.\n     * <p>\n     * Used to test scenario where Futures are returned with a backing call still executing.\n     */\n    private static class SlowCacheableCommand extends TestHystrixObservableCommand<String> {\n\n        private final String value;\n        private final int duration;\n        private volatile boolean executed = false;\n\n        public SlowCacheableCommand(TestCircuitBreaker circuitBreaker, String value, int duration) {\n            super(testPropsBuilder()\n                    .setCommandKey(HystrixCommandKey.Factory.asKey(\"ObservableSlowCacheable\"))\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.value = value;\n            this.duration = duration;\n        }\n\n        @Override\n        protected Observable<String> construct() {\n            executed = true;\n            return Observable.just(value).delay(duration, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.computation())\n                    .doOnNext(new Action1<String>() {\n\n                        @Override\n                        public void call(String t1) {\n                            System.out.println(\"successfully executed\");\n                        }\n\n                    });\n        }\n\n        @Override\n        public String getCacheKey() {\n            return value;\n        }\n    }\n\n    /**\n     * Successful execution - no fallback implementation, circuit-breaker disabled.\n     */\n    private static class TestCommandWithoutCircuitBreaker extends TestHystrixObservableCommand<Boolean> {\n\n        private TestCommandWithoutCircuitBreaker() {\n            super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withCircuitBreakerEnabled(false)));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            System.out.println(\"successfully executed\");\n            return Observable.just(true).subscribeOn(Schedulers.computation());\n        }\n\n    }\n\n    private static class NoRequestCacheTimeoutWithoutFallback extends TestHystrixObservableCommand<Boolean> {\n        public NoRequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionTimeoutInMilliseconds(200).withCircuitBreakerEnabled(false)));\n\n            // we want it to timeout\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    try {\n                        Thread.sleep(500);\n                    } catch (InterruptedException e) {\n                        System.out.println(\">>>> Sleep Interrupted: \" + e.getMessage());\n                        //                    e.printStackTrace();\n                    }\n                    s.onNext(true);\n                    s.onCompleted();\n                }\n\n            }).subscribeOn(Schedulers.computation());\n        }\n\n        @Override\n        public String getCacheKey() {\n            return null;\n        }\n    }\n\n    /**\n     * The run() will take time. Configurable fallback implementation.\n     */\n    private static class TestSemaphoreCommand extends TestHystrixObservableCommand<Boolean> {\n\n        private final long executionSleep;\n\n        private final static int RESULT_SUCCESS = 1;\n        private final static int RESULT_FAILURE = 2;\n        private final static int RESULT_BAD_REQUEST_EXCEPTION = 3;\n\n        private final int resultBehavior;\n\n        private final static int FALLBACK_SUCCESS = 10;\n        private final static int FALLBACK_NOT_IMPLEMENTED = 11;\n        private final static int FALLBACK_FAILURE = 12;\n\n        private final int fallbackBehavior;\n\n        private final static boolean FALLBACK_FAILURE_SYNC = false;\n        private final static boolean FALLBACK_FAILURE_ASYNC = true;\n\n        private final boolean asyncFallbackException;\n\n        private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep, int resultBehavior, int fallbackBehavior) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)\n                            .withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount)));\n            this.executionSleep = executionSleep;\n            this.resultBehavior = resultBehavior;\n            this.fallbackBehavior = fallbackBehavior;\n            this.asyncFallbackException = FALLBACK_FAILURE_ASYNC;\n        }\n\n        private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphore semaphore, long executionSleep, int resultBehavior, int fallbackBehavior) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))\n                    .setExecutionSemaphore(semaphore));\n            this.executionSleep = executionSleep;\n            this.resultBehavior = resultBehavior;\n            this.fallbackBehavior = fallbackBehavior;\n            this.asyncFallbackException = FALLBACK_FAILURE_ASYNC;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n                @Override\n                public void call(Subscriber<? super Boolean> subscriber) {\n                    try {\n                        Thread.sleep(executionSleep);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    if (resultBehavior == RESULT_SUCCESS) {\n                        subscriber.onNext(true);\n                        subscriber.onCompleted();\n                    } else if (resultBehavior == RESULT_FAILURE) {\n                        subscriber.onError(new RuntimeException(\"TestSemaphoreCommand failure\"));\n                    } else if (resultBehavior == RESULT_BAD_REQUEST_EXCEPTION) {\n                        subscriber.onError(new HystrixBadRequestException(\"TestSemaphoreCommand BadRequestException\"));\n                    } else {\n                        subscriber.onError(new IllegalStateException(\"Didn't use a proper enum for result behavior\"));\n                    }\n                }\n            });\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            if (fallbackBehavior == FALLBACK_SUCCESS) {\n                return Observable.just(false);\n            } else if (fallbackBehavior == FALLBACK_FAILURE) {\n                RuntimeException ex = new RuntimeException(\"fallback failure\");\n                if (asyncFallbackException) {\n                    return Observable.error(ex);\n                } else {\n                    throw ex;\n                }\n            } else { //FALLBACK_NOT_IMPLEMENTED\n                return super.resumeWithFallback();\n            }\n        }\n    }\n\n    /**\n     * The construct() will take time once subscribed to. No fallback implementation.\n     *\n     * Used for making sure Thread and Semaphore isolation are separated from each other.\n     */\n    private static class TestThreadIsolationWithSemaphoreSetSmallCommand extends TestHystrixObservableCommand<Boolean> {\n\n        private final Action0 action;\n\n        private TestThreadIsolationWithSemaphoreSetSmallCommand(TestCircuitBreaker circuitBreaker, int poolSize, Action0 action) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(TestThreadIsolationWithSemaphoreSetSmallCommand.class.getSimpleName()))\n                    .setThreadPoolPropertiesDefaults(HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder()\n                            .withCoreSize(poolSize).withMaximumSize(poolSize).withMaxQueueSize(0))\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)\n                            .withExecutionIsolationSemaphoreMaxConcurrentRequests(1)));\n            this.action = action;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    action.call();\n                    s.onNext(true);\n                    s.onCompleted();\n                }\n\n            });\n        }\n    }\n\n    /**\n     * Semaphore based command that allows caller to use latches to know when it has started and signal when it\n     * would like the command to finish\n     */\n    private static class LatchedSemaphoreCommand extends TestHystrixObservableCommand<Boolean> {\n\n        private final CountDownLatch startLatch, waitLatch;\n\n        /**\n         *\n         * @param circuitBreaker circuit breaker (passed in so it may be shared)\n         * @param semaphore semaphore (passed in so it may be shared)\n         * @param startLatch\n         * this command calls {@link CountDownLatch#countDown()} immediately upon running\n         * @param waitLatch\n         *            this command calls {@link CountDownLatch#await()} once it starts\n         *            to run. The caller can use the latch to signal the command to finish\n         */\n        private LatchedSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphoreActual semaphore, CountDownLatch startLatch, CountDownLatch waitLatch) {\n            this(\"Latched\", circuitBreaker, semaphore, startLatch, waitLatch);\n        }\n\n        private LatchedSemaphoreCommand(String commandName, TestCircuitBreaker circuitBreaker, TryableSemaphoreActual semaphore, CountDownLatch startLatch, CountDownLatch waitLatch) {\n            super(testPropsBuilder()\n                    .setCommandKey(HystrixCommandKey.Factory.asKey(commandName))\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionTimeoutEnabled(false)\n                            .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)\n                            .withCircuitBreakerEnabled(false))\n                    .setExecutionSemaphore(semaphore));\n            this.startLatch = startLatch;\n            this.waitLatch = waitLatch;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    //signals caller that run has started\n                    startLatch.countDown();\n                    try {\n                        // waits for caller to countDown latch\n                        waitLatch.await();\n                        s.onNext(true);\n                        s.onCompleted();\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                        s.onNext(false);\n                        s.onCompleted();\n                    }\n                }\n            }).subscribeOn(Schedulers.newThread());\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            return Observable.defer(new Func0<Observable<Boolean>>() {\n                @Override\n                public Observable<Boolean> call() {\n                    startLatch.countDown();\n                    return Observable.just(false);\n                }\n            });\n        }\n    }\n\n    /**\n     * The construct() will take time once subscribed to. Contains fallback.\n     */\n    private static class TestSemaphoreCommandWithFallback extends TestHystrixObservableCommand<Boolean> {\n\n        private final long executionSleep;\n        private final Observable<Boolean> fallback;\n\n        private TestSemaphoreCommandWithFallback(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep, Boolean fallback) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount)));\n            this.executionSleep = executionSleep;\n            this.fallback = Observable.just(fallback);\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    try {\n                        Thread.sleep(executionSleep);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n\n                    s.onNext(true);\n                    s.onCompleted();\n                }\n\n            }).subscribeOn(Schedulers.io());\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            return fallback;\n        }\n\n    }\n\n    private static class InterruptibleCommand extends TestHystrixObservableCommand<Boolean> {\n\n        public InterruptibleCommand(TestCircuitBreaker circuitBreaker, boolean shouldInterrupt) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter()\n                            .withExecutionIsolationThreadInterruptOnTimeout(shouldInterrupt)\n                            .withExecutionTimeoutInMilliseconds(100)));\n        }\n\n        private volatile boolean hasBeenInterrupted;\n\n        public boolean hasBeenInterrupted()\n        {\n            return hasBeenInterrupted;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.defer(new Func0<Observable<Boolean>>() {\n                @Override\n                public Observable<Boolean> call() {\n                    try {\n                        Thread.sleep(1000);\n                    }\n                    catch (InterruptedException e) {\n                        System.out.println(\"Interrupted!\");\n                        e.printStackTrace();\n                        hasBeenInterrupted = true;\n                    }\n\n                    return Observable.just(hasBeenInterrupted);\n                }\n            }).subscribeOn(Schedulers.io());\n\n        }\n    }\n\n    private static class RequestCacheNullPointerExceptionCase extends TestHystrixObservableCommand<Boolean> {\n        public RequestCacheNullPointerExceptionCase(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionTimeoutInMilliseconds(200)));\n            // we want it to timeout\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    try {\n                        Thread.sleep(500);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n\n                    s.onNext(true);\n                    s.onCompleted();\n                }\n\n            }).subscribeOn(Schedulers.computation());\n        }\n\n        @Override\n        protected Observable<Boolean> resumeWithFallback() {\n            return Observable.just(false).subscribeOn(Schedulers.computation());\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class RequestCacheTimeoutWithoutFallback extends TestHystrixObservableCommand<Boolean> {\n        public RequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionTimeoutInMilliseconds(200)));\n            // we want it to timeout\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.create(new OnSubscribe<Boolean>() {\n\n                @Override\n                public void call(Subscriber<? super Boolean> s) {\n                    try {\n                        Thread.sleep(500);\n                    } catch (InterruptedException e) {\n                        System.out.println(\">>>> Sleep Interrupted: \" + e.getMessage());\n                        //                    e.printStackTrace();\n                    }\n\n                    s.onNext(true);\n                    s.onCompleted();\n                }\n\n            }).subscribeOn(Schedulers.computation());\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class RequestCacheThreadRejectionWithoutFallback extends TestHystrixObservableCommand<Boolean> {\n\n        final CountDownLatch completionLatch;\n\n        public RequestCacheThreadRejectionWithoutFallback(TestCircuitBreaker circuitBreaker, CountDownLatch completionLatch) {\n            super(testPropsBuilder()\n                    .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD))\n                    .setCircuitBreaker(circuitBreaker)\n                    .setMetrics(circuitBreaker.metrics)\n                    .setThreadPool(new HystrixThreadPool() {\n\n                        @Override\n                        public ThreadPoolExecutor getExecutor() {\n                            return null;\n                        }\n\n                        @Override\n                        public void markThreadExecution() {\n\n                        }\n\n                        @Override\n                        public void markThreadCompletion() {\n\n                        }\n\n                        @Override\n                        public void markThreadRejection() {\n\n                        }\n\n                        @Override\n                        public boolean isQueueSpaceAvailable() {\n                            // always return false so we reject everything\n                            return false;\n                        }\n\n                        @Override\n                        public Scheduler getScheduler() {\n                            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);\n                        }\n\n                        @Override\n                        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {\n                            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);\n                        }\n\n                    }));\n            this.completionLatch = completionLatch;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            try {\n                if (completionLatch.await(1000, TimeUnit.MILLISECONDS)) {\n                    throw new RuntimeException(\"timed out waiting on completionLatch\");\n                }\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n            return Observable.just(true);\n        }\n\n        @Override\n        public String getCacheKey() {\n            return \"A\";\n        }\n    }\n\n    private static class CommandWithErrorThrown extends TestHystrixObservableCommand<Boolean> {\n\n        private final boolean asyncException;\n\n        public CommandWithErrorThrown(TestCircuitBreaker circuitBreaker, boolean asyncException) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n            this.asyncException = asyncException;\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            Error error = new Error(\"simulated java.lang.Error message\");\n            if (asyncException) {\n                return Observable.error(error);\n            } else {\n                throw error;\n            }\n        }\n    }\n\n    private static class CommandWithCheckedException extends TestHystrixObservableCommand<Boolean> {\n\n        public CommandWithCheckedException(TestCircuitBreaker circuitBreaker) {\n            super(testPropsBuilder()\n                    .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics));\n        }\n\n        @Override\n        protected Observable<Boolean> construct() {\n            return Observable.error(new IOException(\"simulated checked exception message\"));\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixRequestCacheTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.fail;\n\nimport org.junit.Test;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport rx.Subscription;\nimport rx.subjects.ReplaySubject;\n\npublic class HystrixRequestCacheTest {\n\n    @Test\n    public void testCache() {\n        HystrixConcurrencyStrategy strategy = HystrixConcurrencyStrategyDefault.getInstance();\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            HystrixRequestCache cache1 = HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(\"command1\"), strategy);\n            cache1.putIfAbsent(\"valueA\", new TestObservable(\"a1\"));\n            cache1.putIfAbsent(\"valueA\", new TestObservable(\"a2\"));\n            cache1.putIfAbsent(\"valueB\", new TestObservable(\"b1\"));\n\n            HystrixRequestCache cache2 = HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(\"command2\"), strategy);\n            cache2.putIfAbsent(\"valueA\", new TestObservable(\"a3\"));\n\n            assertEquals(\"a1\", cache1.get(\"valueA\").toObservable().toBlocking().last());\n            assertEquals(\"b1\", cache1.get(\"valueB\").toObservable().toBlocking().last());\n\n            assertEquals(\"a3\", cache2.get(\"valueA\").toObservable().toBlocking().last());\n            assertNull(cache2.get(\"valueB\"));\n        } catch (Exception e) {\n            fail(\"Exception: \" + e.getMessage());\n            e.printStackTrace();\n        } finally {\n            context.shutdown();\n        }\n\n        context = HystrixRequestContext.initializeContext();\n        try {\n            // with a new context  the instance should have nothing in it\n            HystrixRequestCache cache = HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(\"command1\"), strategy);\n            assertNull(cache.get(\"valueA\"));\n            assertNull(cache.get(\"valueB\"));\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void testCacheWithoutContext() {\n        HystrixRequestCache.getInstance(\n            HystrixCommandKey.Factory.asKey(\"command1\"),\n            HystrixConcurrencyStrategyDefault.getInstance()\n        ).get(\"any\");\n    }\n\n    @Test\n    public void testClearCache() {\n        HystrixConcurrencyStrategy strategy = HystrixConcurrencyStrategyDefault.getInstance();\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            HystrixRequestCache cache1 = HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(\"command1\"), strategy);\n            cache1.putIfAbsent(\"valueA\", new TestObservable(\"a1\"));\n            assertEquals(\"a1\", cache1.get(\"valueA\").toObservable().toBlocking().last());\n            cache1.clear(\"valueA\");\n            assertNull(cache1.get(\"valueA\"));\n        } catch (Exception e) {\n            fail(\"Exception: \" + e.getMessage());\n            e.printStackTrace();\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    @Test\n    public void testCacheWithoutRequestContext() {\n        HystrixConcurrencyStrategy strategy = HystrixConcurrencyStrategyDefault.getInstance();\n        //HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        try {\n            HystrixRequestCache cache1 = HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey(\"command1\"), strategy);\n            //this should fail, as there's no HystrixRequestContext instance to place the cache into\n            cache1.putIfAbsent(\"valueA\", new TestObservable(\"a1\"));\n            fail(\"should throw an exception on cache put\");\n        } catch (Exception e) {\n            //expected\n            e.printStackTrace();\n        }\n    }\n\n    private static class TestObservable extends HystrixCachedObservable<String> {\n        public TestObservable(String arg) {\n            super(Observable.just(arg));\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixRequestLogTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport rx.Observable;\n\npublic class HystrixRequestLogTest {\n\n    private static final String DIGITS_REGEX = \"\\\\[\\\\d+\";\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @Test\n    public void testSuccess() {\n        new TestCommand(\"A\", false, true).execute();\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"TestCommand[SUCCESS][ms]\", log);\n    }\n\n    @Test\n    public void testSuccessFromCache() {\n        // 1 success\n        new TestCommand(\"A\", false, true).execute();\n        // 4 success from cache\n        new TestCommand(\"A\", false, true).execute();\n        new TestCommand(\"A\", false, true).execute();\n        new TestCommand(\"A\", false, true).execute();\n        new TestCommand(\"A\", false, true).execute();\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"TestCommand[SUCCESS][ms], TestCommand[SUCCESS, RESPONSE_FROM_CACHE][ms]x4\", log);\n    }\n\n    @Test\n    public void testFailWithFallbackSuccess() {\n        // 1 failure\n        new TestCommand(\"A\", true, false).execute();\n        // 4 failures from cache\n        new TestCommand(\"A\", true, false).execute();\n        new TestCommand(\"A\", true, false).execute();\n        new TestCommand(\"A\", true, false).execute();\n        new TestCommand(\"A\", true, false).execute();\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"TestCommand[FAILURE, FALLBACK_SUCCESS][ms], TestCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][ms]x4\", log);\n    }\n\n    @Test\n    public void testFailWithFallbackFailure() {\n        // 1 failure\n        try {\n            new TestCommand(\"A\", true, true).execute();\n        } catch (Exception e) {\n        }\n        // 1 failure from cache\n        try {\n            new TestCommand(\"A\", true, true).execute();\n        } catch (Exception e) {\n        }\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"TestCommand[FAILURE, FALLBACK_FAILURE][ms], TestCommand[FAILURE, FALLBACK_FAILURE, RESPONSE_FROM_CACHE][ms]\", log);\n    }\n\n    @Test\n    public void testTimeout() {\n        Observable<String> result = null;\n\n        // 1 timeout\n        try {\n            for (int i = 0; i < 1; i++) {\n                result = new TestCommand(\"A\", false, false, true).observe();\n            }\n        } catch (Exception e) {\n        }\n        try {\n            result.toBlocking().single();\n        } catch (Throwable ex) {\n            //ex.printStackTrace();\n        }\n        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" -> done with awaiting all observables\");\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"TestCommand[TIMEOUT, FALLBACK_MISSING][ms]\", log);\n    }\n\n    @Test\n    public void testManyTimeouts() {\n        for (int i = 0; i < 10; i++) {\n            testTimeout();\n            ctx.reset();\n        }\n    }\n\n    @Test\n    public void testMultipleCommands() {\n        // 1 success\n        new TestCommand(\"GetData\", \"A\", false, false).execute();\n\n        // 1 success\n        new TestCommand(\"PutData\", \"B\", false, false).execute();\n\n        // 1 success\n        new TestCommand(\"GetValues\", \"C\", false, false).execute();\n\n        // 1 success from cache\n        new TestCommand(\"GetValues\", \"C\", false, false).execute();\n\n        // 1 failure\n        try {\n            new TestCommand(\"A\", true, true).execute();\n        } catch (Exception e) {\n        }\n        // 1 failure from cache\n        try {\n            new TestCommand(\"A\", true, true).execute();\n        } catch (Exception e) {\n        }\n        String log = HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString();\n        // strip the actual count so we can compare reliably\n        log = log.replaceAll(DIGITS_REGEX, \"[\");\n        assertEquals(\"GetData[SUCCESS][ms], PutData[SUCCESS][ms], GetValues[SUCCESS][ms], GetValues[SUCCESS, RESPONSE_FROM_CACHE][ms], TestCommand[FAILURE, FALLBACK_FAILURE][ms], TestCommand[FAILURE, FALLBACK_FAILURE, RESPONSE_FROM_CACHE][ms]\", log);\n    }\n\n    @Test\n    public void testMaxLimit() {\n        for (int i = 0; i < HystrixRequestLog.MAX_STORAGE; i++) {\n            new TestCommand(\"A\", false, true).execute();\n        }\n        // then execute again some more\n        for (int i = 0; i < 10; i++) {\n            new TestCommand(\"A\", false, true).execute();\n        }\n\n        assertEquals(HystrixRequestLog.MAX_STORAGE, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size());\n    }\n\n    private static class TestCommand extends HystrixCommand<String> {\n\n        private final String value;\n        private final boolean fail;\n        private final boolean failOnFallback;\n        private final boolean timeout;\n        private final boolean useFallback;\n        private final boolean useCache;\n\n        public TestCommand(String commandName, String value, boolean fail, boolean failOnFallback) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"RequestLogTestCommand\")).andCommandKey(HystrixCommandKey.Factory.asKey(commandName)));\n            this.value = value;\n            this.fail = fail;\n            this.failOnFallback = failOnFallback;\n            this.timeout = false;\n            this.useFallback = true;\n            this.useCache = true;\n        }\n\n        public TestCommand(String value, boolean fail, boolean failOnFallback) {\n            super(HystrixCommandGroupKey.Factory.asKey(\"RequestLogTestCommand\"));\n            this.value = value;\n            this.fail = fail;\n            this.failOnFallback = failOnFallback;\n            this.timeout = false;\n            this.useFallback = true;\n            this.useCache = true;\n        }\n\n        public TestCommand(String value, boolean fail, boolean failOnFallback, boolean timeout) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"RequestLogTestCommand\")).andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));\n            this.value = value;\n            this.fail = fail;\n            this.failOnFallback = failOnFallback;\n            this.timeout = timeout;\n            this.useFallback = false;\n            this.useCache = false;\n        }\n\n        @Override\n        protected String run() {\n            System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis());\n            if (fail) {\n                throw new RuntimeException(\"forced failure\");\n            } else if (timeout) {\n                try {\n                    Thread.sleep(10000);\n                    System.out.println(\"Woke up from sleep!\");\n                } catch (InterruptedException ex) {\n                    System.out.println(Thread.currentThread().getName() + \" Interrupted by timeout\");\n                }\n            }\n            return value;\n        }\n\n        @Override\n        protected String getFallback() {\n            if (useFallback) {\n                if (failOnFallback) {\n                    throw new RuntimeException(\"forced fallback failure\");\n                } else {\n                    return value + \"-fallback\";\n                }\n            } else {\n                throw new UnsupportedOperationException(\"no fallback implemented\");\n            }\n        }\n\n        @Override\n        protected String getCacheKey() {\n            if (useCache) {\n                return value;\n            } else {\n                return null;\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixSubclassCommandTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class HystrixSubclassCommandTest {\n\n    private final static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"GROUP\");\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    @Test\n    public void testFallback() {\n        HystrixCommand<Integer> superCmd = new SuperCommand(\"cache\", false);\n        assertEquals(2, superCmd.execute().intValue());\n\n        HystrixCommand<Integer> subNoOverridesCmd = new SubCommandNoOverride(\"cache\", false);\n        assertEquals(2, subNoOverridesCmd.execute().intValue());\n\n        HystrixCommand<Integer> subOverriddenFallbackCmd = new SubCommandOverrideFallback(\"cache\", false);\n        assertEquals(3, subOverriddenFallbackCmd.execute().intValue());\n    }\n\n    @Test\n    public void testRequestCacheSuperClass() {\n        HystrixCommand<Integer> superCmd1 = new SuperCommand(\"cache\", true);\n        assertEquals(1, superCmd1.execute().intValue());\n        HystrixCommand<Integer> superCmd2 = new SuperCommand(\"cache\", true);\n        assertEquals(1, superCmd2.execute().intValue());\n        HystrixCommand<Integer> superCmd3 = new SuperCommand(\"no-cache\", true);\n        assertEquals(1, superCmd3.execute().intValue());\n        System.out.println(\"REQ LOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        HystrixRequestLog reqLog = HystrixRequestLog.getCurrentRequest();\n        assertEquals(3, reqLog.getAllExecutedCommands().size());\n        List<HystrixInvokableInfo<?>> infos = new ArrayList<HystrixInvokableInfo<?>>(reqLog.getAllExecutedCommands());\n        HystrixInvokableInfo<?> info1 = infos.get(0);\n        assertEquals(\"SuperCommand\", info1.getCommandKey().name());\n        assertEquals(1, info1.getExecutionEvents().size());\n        HystrixInvokableInfo<?> info2 = infos.get(1);\n        assertEquals(\"SuperCommand\", info2.getCommandKey().name());\n        assertEquals(2, info2.getExecutionEvents().size());\n        assertEquals(HystrixEventType.RESPONSE_FROM_CACHE, info2.getExecutionEvents().get(1));\n        HystrixInvokableInfo<?> info3 = infos.get(2);\n        assertEquals(\"SuperCommand\", info3.getCommandKey().name());\n        assertEquals(1, info3.getExecutionEvents().size());\n    }\n\n    @Test\n    public void testRequestCacheSubclassNoOverrides() {\n        HystrixCommand<Integer> subCmd1 = new SubCommandNoOverride(\"cache\", true);\n        assertEquals(1, subCmd1.execute().intValue());\n        HystrixCommand<Integer> subCmd2 = new SubCommandNoOverride(\"cache\", true);\n        assertEquals(1, subCmd2.execute().intValue());\n        HystrixCommand<Integer> subCmd3 = new SubCommandNoOverride(\"no-cache\", true);\n        assertEquals(1, subCmd3.execute().intValue());\n        System.out.println(\"REQ LOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        HystrixRequestLog reqLog = HystrixRequestLog.getCurrentRequest();\n        assertEquals(3, reqLog.getAllExecutedCommands().size());\n        List<HystrixInvokableInfo<?>> infos = new ArrayList<HystrixInvokableInfo<?>>(reqLog.getAllExecutedCommands());\n        HystrixInvokableInfo<?> info1 = infos.get(0);\n        assertEquals(\"SubCommandNoOverride\", info1.getCommandKey().name());\n        assertEquals(1, info1.getExecutionEvents().size());\n        HystrixInvokableInfo<?> info2 = infos.get(1);\n        assertEquals(\"SubCommandNoOverride\", info2.getCommandKey().name());\n        assertEquals(2, info2.getExecutionEvents().size());\n        assertEquals(HystrixEventType.RESPONSE_FROM_CACHE, info2.getExecutionEvents().get(1));\n        HystrixInvokableInfo<?> info3 = infos.get(2);\n        assertEquals(\"SubCommandNoOverride\", info3.getCommandKey().name());\n        assertEquals(1, info3.getExecutionEvents().size());\n    }\n\n    @Test\n    public void testRequestLogSuperClass() {\n        HystrixCommand<Integer> superCmd = new SuperCommand(\"cache\", true);\n        assertEquals(1, superCmd.execute().intValue());\n        System.out.println(\"REQ LOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        HystrixRequestLog reqLog = HystrixRequestLog.getCurrentRequest();\n        assertEquals(1, reqLog.getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> info = reqLog.getAllExecutedCommands().iterator().next();\n        assertEquals(\"SuperCommand\", info.getCommandKey().name());\n    }\n\n    @Test\n    public void testRequestLogSubClassNoOverrides() {\n        HystrixCommand<Integer> subCmd = new SubCommandNoOverride(\"cache\", true);\n        assertEquals(1, subCmd.execute().intValue());\n        System.out.println(\"REQ LOG : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        HystrixRequestLog reqLog = HystrixRequestLog.getCurrentRequest();\n        assertEquals(1, reqLog.getAllExecutedCommands().size());\n        HystrixInvokableInfo<?> info = reqLog.getAllExecutedCommands().iterator().next();\n        assertEquals(\"SubCommandNoOverride\", info.getCommandKey().name());\n    }\n\n    public static class SuperCommand extends HystrixCommand<Integer> {\n        private final String uniqueArg;\n        private final boolean shouldSucceed;\n\n        SuperCommand(String uniqueArg, boolean shouldSucceed) {\n            super(Setter.withGroupKey(groupKey));\n            this.uniqueArg = uniqueArg;\n            this.shouldSucceed = shouldSucceed;\n        }\n\n        @Override\n        protected Integer run() throws Exception {\n            if (shouldSucceed) {\n                return 1;\n            } else {\n                throw new RuntimeException(\"unit test failure\");\n            }\n        }\n\n        @Override\n        protected Integer getFallback() {\n            return 2;\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return uniqueArg;\n        }\n    }\n\n    public static class SubCommandNoOverride extends SuperCommand {\n        SubCommandNoOverride(String uniqueArg, boolean shouldSucceed) {\n            super(uniqueArg, shouldSucceed);\n        }\n    }\n\n    public static class SubCommandOverrideFallback extends SuperCommand {\n        SubCommandOverrideFallback(String uniqueArg, boolean shouldSucceed) {\n            super(uniqueArg, shouldSucceed);\n        }\n\n        @Override\n        protected Integer getFallback() {\n            return 3;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport org.junit.Before;\n\nimport com.netflix.hystrix.HystrixCommand.Setter;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Func0;\nimport rx.schedulers.Schedulers;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixTest {\n    @Before\n    public void reset() {\n        Hystrix.reset();\n    }\n\n    @Test\n    public void testNotInThread() {\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n      public void testInsideHystrixThreadViaExecute() {\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"CommandName\"))) {\n\n            @Override\n            protected Boolean run() {\n                assertEquals(\"CommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                assertEquals(1, Hystrix.getCommandCount());\n                return Hystrix.getCurrentThreadExecutingCommand() != null;\n            }\n\n        };\n\n        assertTrue(command.execute());\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n        assertEquals(0, Hystrix.getCommandCount());\n    }\n\n    @Test\n    public void testInsideHystrixThreadViaObserve() {\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"CommandName\"))) {\n\n            @Override\n            protected Boolean run() {\n                try {\n                    //give the caller thread a chance to check that no thread locals are set on it\n                    Thread.sleep(100);\n                } catch (InterruptedException ex) {\n                    return false;\n                }\n                assertEquals(\"CommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                assertEquals(1, Hystrix.getCommandCount());\n                return Hystrix.getCurrentThreadExecutingCommand() != null;\n            }\n\n        };\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        command.observe().subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean value) {\n                System.out.println(\"OnNext : \" + value);\n                assertTrue(value);\n                assertEquals(\"CommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                assertEquals(1, Hystrix.getCommandCount());\n            }\n        });\n\n        try {\n            assertNull(Hystrix.getCurrentThreadExecutingCommand());\n            assertEquals(0, Hystrix.getCommandCount());\n            latch.await();\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n        assertEquals(0, Hystrix.getCommandCount());\n    }\n\n    @Test\n    public void testInsideNestedHystrixThread() {\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"OuterCommand\"))) {\n\n            @Override\n            protected Boolean run() {\n\n                assertEquals(\"OuterCommand\", Hystrix.getCurrentThreadExecutingCommand().name());\n                System.out.println(\"Outer Thread : \" + Thread.currentThread().getName());\n                //should be a single execution on this thread\n                assertEquals(1, Hystrix.getCommandCount());\n\n                if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n                    throw new RuntimeException(\"BEFORE expected it to run inside a thread\");\n                }\n\n                HystrixCommand<Boolean> command2 = new HystrixCommand<Boolean>(Setter\n                        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                        .andCommandKey(HystrixCommandKey.Factory.asKey(\"InnerCommand\"))) {\n\n                    @Override\n                    protected Boolean run() {\n                        assertEquals(\"InnerCommand\", Hystrix.getCurrentThreadExecutingCommand().name());\n                        System.out.println(\"Inner Thread : \" + Thread.currentThread().getName());\n                        //should be a single execution on this thread, since outer/inner are on different threads\n                        assertEquals(1, Hystrix.getCommandCount());\n                        return Hystrix.getCurrentThreadExecutingCommand() != null;\n                    }\n\n                };\n\n                if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n                    throw new RuntimeException(\"AFTER expected it to run inside a thread\");\n                }\n\n                return command2.execute();\n            }\n\n        };\n\n        assertTrue(command.execute());\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n    public void testInsideHystrixSemaphoreExecute() {\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"SemaphoreIsolatedCommandName\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Boolean run() {\n                assertEquals(\"SemaphoreIsolatedCommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                System.out.println(\"Semaphore Thread : \" + Thread.currentThread().getName());\n                //should be a single execution on the caller thread (since it's busy here)\n                assertEquals(1, Hystrix.getCommandCount());\n                return Hystrix.getCurrentThreadExecutingCommand() != null;\n            }\n\n        };\n\n        // it should be true for semaphore isolation as well\n        assertTrue(command.execute());\n        // and then be null again once done\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n    public void testInsideHystrixSemaphoreQueue() throws Exception {\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"SemaphoreIsolatedCommandName\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Boolean run() {\n                assertEquals(\"SemaphoreIsolatedCommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                System.out.println(\"Semaphore Thread : \" + Thread.currentThread().getName());\n                //should be a single execution on the caller thread (since it's busy here)\n                assertEquals(1, Hystrix.getCommandCount());\n                return Hystrix.getCurrentThreadExecutingCommand() != null;\n            }\n\n        };\n\n        // it should be true for semaphore isolation as well\n        assertTrue(command.queue().get());\n        // and then be null again once done\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n    public void testInsideHystrixSemaphoreObserve() throws Exception {\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"SemaphoreIsolatedCommandName\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Boolean run() {\n                assertEquals(\"SemaphoreIsolatedCommandName\", Hystrix.getCurrentThreadExecutingCommand().name());\n                System.out.println(\"Semaphore Thread : \" + Thread.currentThread().getName());\n                //should be a single execution on the caller thread (since it's busy here)\n                assertEquals(1, Hystrix.getCommandCount());\n                return Hystrix.getCurrentThreadExecutingCommand() != null;\n            }\n\n        };\n\n        // it should be true for semaphore isolation as well\n        assertTrue(command.toObservable().toBlocking().single());\n        // and then be null again once done\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n    public void testThreadNestedInsideHystrixSemaphore() {\n\n        HystrixCommand<Boolean> command = new HystrixCommand<Boolean>(Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"OuterSemaphoreCommand\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))) {\n\n            @Override\n            protected Boolean run() {\n\n                assertEquals(\"OuterSemaphoreCommand\", Hystrix.getCurrentThreadExecutingCommand().name());\n                System.out.println(\"Outer Semaphore Thread : \" + Thread.currentThread().getName());\n                //should be a single execution on the caller thread\n                assertEquals(1, Hystrix.getCommandCount());\n                if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n                    throw new RuntimeException(\"BEFORE expected it to run inside a semaphore\");\n                }\n\n                HystrixCommand<Boolean> command2 = new HystrixCommand<Boolean>(Setter\n                        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TestUtil\"))\n                        .andCommandKey(HystrixCommandKey.Factory.asKey(\"InnerCommand\"))) {\n\n                    @Override\n                    protected Boolean run() {\n                        assertEquals(\"InnerCommand\", Hystrix.getCurrentThreadExecutingCommand().name());\n                        System.out.println(\"Inner Thread : \" + Thread.currentThread().getName());\n                        //should be a single execution on the thread isolating the second command\n                        assertEquals(1, Hystrix.getCommandCount());\n                        return Hystrix.getCurrentThreadExecutingCommand() != null;\n                    }\n\n                };\n\n                if (Hystrix.getCurrentThreadExecutingCommand() == null) {\n                    throw new RuntimeException(\"AFTER expected it to run inside a semaphore\");\n                }\n\n                return command2.execute();\n            }\n\n        };\n\n        assertTrue(command.execute());\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n    }\n\n    @Test\n    public void testSemaphoreIsolatedSynchronousHystrixObservableCommand() {\n        HystrixObservableCommand<Integer> observableCmd = new SynchronousObservableCommand();\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        observableCmd.observe().subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer value) {\n                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" SyncObservable latched Subscriber OnNext : \" + value);\n            }\n        });\n\n        try {\n            assertNull(Hystrix.getCurrentThreadExecutingCommand());\n            assertEquals(0, Hystrix.getCommandCount());\n            latch.await();\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n        assertEquals(0, Hystrix.getCommandCount());\n    }\n\n//    @Test\n//    public void testSemaphoreIsolatedAsynchronousHystrixObservableCommand() {\n//        HystrixObservableCommand<Integer> observableCmd = new AsynchronousObservableCommand();\n//\n//        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n//\n//        final CountDownLatch latch = new CountDownLatch(1);\n//\n//        observableCmd.observe().subscribe(new Subscriber<Integer>() {\n//            @Override\n//            public void onCompleted() {\n//                latch.countDown();\n//            }\n//\n//            @Override\n//            public void onError(Throwable e) {\n//                fail(e.getMessage());\n//                latch.countDown();\n//            }\n//\n//            @Override\n//            public void onNext(Integer value) {\n//                System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" AsyncObservable latched Subscriber OnNext : \" + value);\n//            }\n//        });\n//\n//        try {\n//            assertNull(Hystrix.getCurrentThreadExecutingCommand());\n//            assertEquals(0, Hystrix.getCommandCount());\n//            latch.await();\n//        } catch (InterruptedException ex) {\n//            fail(ex.getMessage());\n//        }\n//\n//        assertNull(Hystrix.getCurrentThreadExecutingCommand());\n//        assertEquals(0, Hystrix.getCommandCount());\n//    }\n\n    @Test\n    public void testMultipleSemaphoreObservableCommandsInFlight() throws InterruptedException {\n        int NUM_COMMANDS = 50;\n        List<Observable<Integer>> commands = new ArrayList<Observable<Integer>>();\n        for (int i = 0; i < NUM_COMMANDS; i++) {\n            commands.add(Observable.defer(new Func0<Observable<Integer>>() {\n                @Override\n                public Observable<Integer> call() {\n                    return new AsynchronousObservableCommand().observe();\n                }\n            }));\n        }\n\n        final AtomicBoolean exceptionFound = new AtomicBoolean(false);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        Observable.merge(commands).subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(\"OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(\"OnError : \" + e);\n                e.printStackTrace();\n                exceptionFound.set(true);\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Integer n) {\n                System.out.println(\"OnNext : \" + n + \" : \" + Thread.currentThread().getName() + \" : \" + Hystrix.getCommandCount());// + \" : \" + Hystrix.getCurrentThreadExecutingCommand().name() + \" : \" + Hystrix.getCommandCount());\n            }\n        });\n\n        latch.await();\n\n        assertFalse(exceptionFound.get());\n    }\n\n    //see https://github.com/Netflix/Hystrix/issues/280\n    @Test\n    public void testResetCommandProperties() {\n        HystrixCommand<Boolean> cmd1 = new ResettableCommand(100, 1, 10);\n        assertEquals(100L, (long) cmd1.getProperties().executionTimeoutInMilliseconds().get());\n        assertEquals(1L, (long) cmd1.getProperties().executionIsolationSemaphoreMaxConcurrentRequests().get());\n        //assertEquals(10L, (long) cmd1.threadPool.getExecutor()..getCorePoolSize());\n\n        Hystrix.reset();\n\n        HystrixCommand<Boolean> cmd2 = new ResettableCommand(700, 2, 40);\n        assertEquals(700L, (long) cmd2.getProperties().executionTimeoutInMilliseconds().get());\n        assertEquals(2L, (long) cmd2.getProperties().executionIsolationSemaphoreMaxConcurrentRequests().get());\n        //assertEquals(40L, (long) cmd2.threadPool.getExecutor().getCorePoolSize());\n\t}\n\n    private static class SynchronousObservableCommand extends HystrixObservableCommand<Integer> {\n\n        protected SynchronousObservableCommand() {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GROUP\"))\n                            .andCommandKey(HystrixCommandKey.Factory.asKey(\"SyncObservable\"))\n                            .andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withExecutionIsolationSemaphoreMaxConcurrentRequests(1000))\n            );\n        }\n\n        @Override\n        protected Observable<Integer> construct() {\n            return Observable.create(new Observable.OnSubscribe<Integer>() {\n                @Override\n                public void call(Subscriber<? super Integer> subscriber) {\n                    try {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" SyncCommand construct()\");\n                        assertEquals(\"SyncObservable\", Hystrix.getCurrentThreadExecutingCommand().name());\n                        assertEquals(1, Hystrix.getCommandCount());\n                        Thread.sleep(10);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" SyncCommand construct() -> OnNext(1)\");\n                        subscriber.onNext(1);\n                        Thread.sleep(10);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" SyncCommand construct() -> OnNext(2)\");\n                        subscriber.onNext(2);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" SyncCommand construct() -> OnCompleted\");\n                        subscriber.onCompleted();\n                    } catch (Throwable ex) {\n                        subscriber.onError(ex);\n                    }\n                }\n            });\n        }\n    }\n\n    private static class AsynchronousObservableCommand extends HystrixObservableCommand<Integer> {\n\n        protected AsynchronousObservableCommand() {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GROUP\"))\n                            .andCommandKey(HystrixCommandKey.Factory.asKey(\"AsyncObservable\"))\n                            .andCommandPropertiesDefaults(new HystrixCommandProperties.Setter().withExecutionIsolationSemaphoreMaxConcurrentRequests(1000))\n            );\n        }\n\n        @Override\n        protected Observable<Integer> construct() {\n            return Observable.create(new Observable.OnSubscribe<Integer>() {\n                @Override\n                public void call(Subscriber<? super Integer> subscriber) {\n                    try {\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" AsyncCommand construct()\");\n                        Thread.sleep(10);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" AsyncCommand construct() -> OnNext(1)\");\n                        subscriber.onNext(1);\n                        Thread.sleep(10);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" AsyncCommand construct() -> OnNext(2)\");\n                        subscriber.onNext(2);\n                        System.out.println(Thread.currentThread().getName() + \" : \" + System.currentTimeMillis() + \" AsyncCommand construct() -> OnCompleted\");\n                        subscriber.onCompleted();\n                    } catch (Throwable ex) {\n                        subscriber.onError(ex);\n                    }\n                }\n            }).subscribeOn(Schedulers.computation());\n        }\n    }\n\n    private static class ResettableCommand extends HystrixCommand<Boolean> {\n        ResettableCommand(int timeout, int semaphoreCount, int poolCoreSize) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GROUP\"))\n                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                            .withExecutionTimeoutInMilliseconds(timeout)\n                    .withExecutionIsolationSemaphoreMaxConcurrentRequests(semaphoreCount))\n                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(poolCoreSize)));\n        }\n\n        @Override\n        protected Boolean run() throws Exception {\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolMetricsTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.metric.consumer.RollingThreadPoolEventCounterStream;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.Collection;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class HystrixThreadPoolMetricsTest {\n\n    private static final HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"HystrixThreadPoolMetrics-UnitTest\");\n    private static final HystrixThreadPoolKey tpKey = HystrixThreadPoolKey.Factory.asKey(\"HystrixThreadPoolMetrics-ThreadPool\");\n\n    @Before\n    public void resetAll() {\n        HystrixThreadPoolMetrics.reset();\n    }\n\n    @Test\n    public void shouldYieldNoExecutedTasksOnStartup() throws Exception {\n        //given\n        final Collection<HystrixThreadPoolMetrics> instances = HystrixThreadPoolMetrics.getInstances();\n\n        //then\n        assertEquals(0, instances.size());\n\n    }\n    @Test\n    public void shouldReturnOneExecutedTask() throws Exception {\n        //given\n        RollingThreadPoolEventCounterStream.getInstance(tpKey, 10, 100).startCachingStreamValuesIfUnstarted();\n\n        new NoOpHystrixCommand().execute();\n        Thread.sleep(100);\n\n        final Collection<HystrixThreadPoolMetrics> instances = HystrixThreadPoolMetrics.getInstances();\n\n        //then\n        assertEquals(1, instances.size());\n        HystrixThreadPoolMetrics metrics = instances.iterator().next();\n        assertEquals(1, instances.iterator().next().getRollingCountThreadsExecuted());\n    }\n\n    private static class NoOpHystrixCommand extends HystrixCommand<Void> {\n        public NoOpHystrixCommand() {\n            super(Setter.withGroupKey(groupKey)\n                    .andThreadPoolKey(tpKey)\n                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withMetricsRollingStatisticalWindowInMilliseconds(100)));\n        }\n\n        @Override\n        protected Void run() throws Exception {\n            System.out.println(\"Run in thread : \" + Thread.currentThread().getName());\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolPropertiesTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.After;\nimport org.junit.Test;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\n\npublic class HystrixThreadPoolPropertiesTest {\n\n    /**\n     * Base properties for unit testing.\n     */\n        /* package */static HystrixThreadPoolProperties.Setter getUnitTestPropertiesBuilder() {\n        return HystrixThreadPoolProperties.Setter()\n                .withCoreSize(10)// core size of thread pool\n                .withMaximumSize(15) //maximum size of thread pool\n                .withKeepAliveTimeMinutes(1)// minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size)\n                .withMaxQueueSize(100)// size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject)\n                .withQueueSizeRejectionThreshold(10)// number of items in queue at which point we reject (this can be dyamically changed)\n                .withMetricsRollingStatisticalWindowInMilliseconds(10000)// milliseconds for rolling number\n                .withMetricsRollingStatisticalWindowBuckets(10);// number of buckets in rolling number (10 1-second buckets)\n    }\n\n    /**\n     * Return a static representation of the properties with values from the Builder so that UnitTests can create properties that are not affected by the actual implementations which pick up their\n     * values dynamically.\n     *\n     * @param builder builder for a {@link HystrixThreadPoolProperties}\n     * @return HystrixThreadPoolProperties\n     */\n        /* package */static HystrixThreadPoolProperties asMock(final HystrixThreadPoolProperties.Setter builder) {\n        return new HystrixThreadPoolProperties(TestThreadPoolKey.TEST) {\n\n            @Override\n            public HystrixProperty<Integer> coreSize() {\n                return HystrixProperty.Factory.asProperty(builder.getCoreSize());\n            }\n\n            @Override\n            public HystrixProperty<Integer> maximumSize() {\n                return HystrixProperty.Factory.asProperty(builder.getMaximumSize());\n            }\n\n            @Override\n            public HystrixProperty<Integer> keepAliveTimeMinutes() {\n                return HystrixProperty.Factory.asProperty(builder.getKeepAliveTimeMinutes());\n            }\n\n            @Override\n            public HystrixProperty<Integer> maxQueueSize() {\n                return HystrixProperty.Factory.asProperty(builder.getMaxQueueSize());\n            }\n\n            @Override\n            public HystrixProperty<Integer> queueSizeRejectionThreshold() {\n                return HystrixProperty.Factory.asProperty(builder.getQueueSizeRejectionThreshold());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowInMilliseconds());\n            }\n\n            @Override\n            public HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets() {\n                return HystrixProperty.Factory.asProperty(builder.getMetricsRollingStatisticalWindowBuckets());\n            }\n\n        };\n\n    }\n\n    private static enum TestThreadPoolKey implements HystrixThreadPoolKey {\n        TEST\n    }\n\n    @After\n    public void cleanup() {\n        ConfigurationManager.getConfigInstance().clear();\n    }\n\n    @Test\n    public void testSetNeitherCoreNorMaximumSizeWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_maximumSize, properties.maximumSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetNeitherCoreNorMaximumSizeWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_maximumSize, properties.maximumSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_maximumSize, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeOnlyWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(14)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(14, properties.coreSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_maximumSize, properties.maximumSize().get().intValue());\n        assertEquals(14, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeOnlyWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(14)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(14, properties.coreSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_maximumSize, properties.maximumSize().get().intValue());\n        assertEquals(14, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetMaximumSizeOnlyLowerThanDefaultCoreSizeWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withMaximumSize(3)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(3, properties.maximumSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetMaximumSizeOnlyLowerThanDefaultCoreSizeWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withMaximumSize(3)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(3, properties.maximumSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetMaximumSizeOnlyGreaterThanDefaultCoreSizeWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withMaximumSize(21)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(21, properties.maximumSize().get().intValue());\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetMaximumSizeOnlyGreaterThanDefaultCoreSizeWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withMaximumSize(21)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(HystrixThreadPoolProperties.default_coreSize, properties.coreSize().get().intValue());\n        assertEquals(21, properties.maximumSize().get().intValue());\n        assertEquals(21, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeLessThanMaximumSizeWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(2)\n                        .withMaximumSize(8)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(2, properties.coreSize().get().intValue());\n        assertEquals(8, properties.maximumSize().get().intValue());\n        assertEquals(2, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeLessThanMaximumSizeWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(2)\n                        .withMaximumSize(8)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(2, properties.coreSize().get().intValue());\n        assertEquals(8, properties.maximumSize().get().intValue());\n        assertEquals(8, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeEqualToMaximumSizeDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(7)\n                        .withMaximumSize(7)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(7, properties.coreSize().get().intValue());\n        assertEquals(7, properties.maximumSize().get().intValue());\n        assertEquals(7, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeEqualToMaximumSizeDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(7)\n                        .withMaximumSize(7)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(7, properties.coreSize().get().intValue());\n        assertEquals(7, properties.maximumSize().get().intValue());\n        assertEquals(7, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeGreaterThanMaximumSizeWithDivergenceDisallowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(12)\n                        .withMaximumSize(8)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(false)) {\n        };\n\n        assertEquals(12, properties.coreSize().get().intValue());\n        assertEquals(8, properties.maximumSize().get().intValue());\n        assertEquals(12, (int) properties.actualMaximumSize());\n    }\n\n    @Test\n    public void testSetCoreSizeGreaterThanMaximumSizeWithDivergenceAllowed() {\n        HystrixThreadPoolProperties properties = new HystrixThreadPoolProperties(TestThreadPoolKey.TEST,\n                HystrixThreadPoolProperties.Setter()\n                        .withCoreSize(12)\n                        .withMaximumSize(8)\n                        .withAllowMaximumSizeToDivergeFromCoreSize(true)) {\n        };\n\n        assertEquals(12, properties.coreSize().get().intValue());\n        assertEquals(8, properties.maximumSize().get().intValue());\n        assertEquals(12, (int) properties.actualMaximumSize());\n    }\n}\n\n\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/HystrixThreadPoolTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertThat;\nimport static org.junit.Assert.assertTrue;\nimport static org.hamcrest.core.Is.is;\n\nimport com.netflix.hystrix.HystrixThreadPool.Factory;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.*;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherFactory;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport rx.Scheduler;\nimport rx.functions.Action0;\n\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class HystrixThreadPoolTest {\n    @Before\n    public void setup() {\n        Hystrix.reset();\n    }\n\n    @Test\n    public void testShutdown() {\n        // other unit tests will probably have run before this so get the count\n        int count = Factory.threadPools.size();\n\n        HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey(\"threadPoolFactoryTest\"),\n                HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder());\n\n        assertEquals(count + 1, Factory.threadPools.size());\n        assertFalse(pool.getExecutor().isShutdown());\n\n        Factory.shutdown();\n\n        // ensure all pools were removed from the cache\n        assertEquals(0, Factory.threadPools.size());\n        assertTrue(pool.getExecutor().isShutdown());\n    }\n\n    @Test\n    public void testShutdownWithWait() {\n        // other unit tests will probably have run before this so get the count\n        int count = Factory.threadPools.size();\n\n        HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey(\"threadPoolFactoryTest\"),\n                HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder());\n\n        assertEquals(count + 1, Factory.threadPools.size());\n        assertFalse(pool.getExecutor().isShutdown());\n\n        Factory.shutdown(1, TimeUnit.SECONDS);\n\n        // ensure all pools were removed from the cache\n        assertEquals(0, Factory.threadPools.size());\n        assertTrue(pool.getExecutor().isShutdown());\n    }\n\n    private static class HystrixMetricsPublisherThreadPoolContainer implements HystrixMetricsPublisherThreadPool {\n        private final HystrixThreadPoolMetrics hystrixThreadPoolMetrics;\n\n        private HystrixMetricsPublisherThreadPoolContainer(HystrixThreadPoolMetrics hystrixThreadPoolMetrics) {\n            this.hystrixThreadPoolMetrics = hystrixThreadPoolMetrics;\n        }\n\n        @Override\n        public void initialize() {\n        }\n\n        public HystrixThreadPoolMetrics getHystrixThreadPoolMetrics() {\n            return hystrixThreadPoolMetrics;\n        }\n    }\n\n    @Test\n    public void ensureThreadPoolInstanceIsTheOneRegisteredWithMetricsPublisherAndThreadPoolCache() throws IllegalAccessException, NoSuchFieldException {\n        HystrixPlugins.getInstance().registerMetricsPublisher(new HystrixMetricsPublisher() {\n            @Override\n            public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n                return new HystrixMetricsPublisherThreadPoolContainer(metrics);\n            }\n        });\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"threadPoolFactoryConcurrencyTest\");\n        HystrixThreadPool poolOne = new HystrixThreadPool.HystrixThreadPoolDefault(\n                threadPoolKey, HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder());\n        HystrixThreadPool poolTwo = new HystrixThreadPool.HystrixThreadPoolDefault(\n                threadPoolKey, HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder());\n\n        assertThat(poolOne.getExecutor(), is(poolTwo.getExecutor())); //Now that we get the threadPool from the metrics object, this will always be equal\n        HystrixMetricsPublisherThreadPoolContainer hystrixMetricsPublisherThreadPool =\n                (HystrixMetricsPublisherThreadPoolContainer)HystrixMetricsPublisherFactory\n                        .createOrRetrievePublisherForThreadPool(threadPoolKey, null, null);\n        ThreadPoolExecutor threadPoolExecutor = hystrixMetricsPublisherThreadPool.getHystrixThreadPoolMetrics().getThreadPool();\n\n        //assert that both HystrixThreadPools share the same ThreadPoolExecutor as the one in HystrixMetricsPublisherThreadPool\n        assertTrue(threadPoolExecutor.equals(poolOne.getExecutor()) && threadPoolExecutor.equals(poolTwo.getExecutor()));\n        assertFalse(threadPoolExecutor.isShutdown());\n\n        //Now the HystrixThreadPool ALWAYS has the same reference to the ThreadPoolExecutor so that it no longer matters which\n        //wins to be inserted into the HystrixThreadPool.Factory.threadPools cache.\n    }\n\n    @Test(timeout = 2500)\n    public void testUnsubscribeHystrixThreadPool() throws InterruptedException {\n        // methods are package-private so can't test it somewhere else\n        HystrixThreadPool pool = Factory.getInstance(HystrixThreadPoolKey.Factory.asKey(\"threadPoolFactoryTest\"),\n                HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder());\n        \n        final AtomicBoolean interrupted = new AtomicBoolean();\n        final CountDownLatch start = new CountDownLatch(1);\n        final CountDownLatch end = new CountDownLatch(1);\n\n        HystrixContextScheduler hcs = new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), pool);\n\n        Scheduler.Worker w = hcs.createWorker();\n\n        try {\n            w.schedule(new Action0() {\n                @Override\n                public void call() {\n                    start.countDown();\n                    try {\n                        try {\n                            Thread.sleep(5000);\n                        } catch (InterruptedException ex) {\n                            interrupted.set(true);\n                        }\n                    } finally {\n                        end.countDown();\n                    }\n                }\n            });\n            \n            start.await();\n            \n            w.unsubscribe();\n            \n            end.await();\n            \n            Factory.shutdown();\n            \n            assertTrue(interrupted.get());\n        } finally {\n            w.unsubscribe();\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/InspectableBuilder.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\npublic interface InspectableBuilder {\n    public TestCommandBuilder getBuilder();\n\n    public enum CommandKeyForUnitTest implements HystrixCommandKey {\n        KEY_ONE, KEY_TWO\n    }\n\n    public enum CommandGroupForUnitTest implements HystrixCommandGroupKey {\n        OWNER_ONE, OWNER_TWO\n    }\n\n    public enum ThreadPoolKeyForUnitTest implements HystrixThreadPoolKey {\n        THREAD_POOL_ONE, THREAD_POOL_TWO\n    }\n\n    public static class TestCommandBuilder {\n        HystrixCommandGroupKey owner = CommandGroupForUnitTest.OWNER_ONE;\n        HystrixCommandKey dependencyKey = null;\n        HystrixThreadPoolKey threadPoolKey = null;\n        HystrixCircuitBreaker circuitBreaker;\n        HystrixThreadPool threadPool = null;\n        HystrixCommandProperties.Setter commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter();\n        HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolPropertiesTest.getUnitTestPropertiesBuilder();\n        HystrixCommandMetrics metrics;\n        AbstractCommand.TryableSemaphore fallbackSemaphore = null;\n        AbstractCommand.TryableSemaphore executionSemaphore = null;\n        TestableExecutionHook executionHook = new TestableExecutionHook();\n\n        TestCommandBuilder(HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy) {\n            this.commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy);\n        }\n\n        TestCommandBuilder setOwner(HystrixCommandGroupKey owner) {\n            this.owner = owner;\n            return this;\n        }\n\n        TestCommandBuilder setCommandKey(HystrixCommandKey dependencyKey) {\n            this.dependencyKey = dependencyKey;\n            return this;\n        }\n\n        TestCommandBuilder setThreadPoolKey(HystrixThreadPoolKey threadPoolKey) {\n            this.threadPoolKey = threadPoolKey;\n            return this;\n        }\n\n        TestCommandBuilder setCircuitBreaker(HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker) {\n            this.circuitBreaker = circuitBreaker;\n            if (circuitBreaker != null) {\n                this.metrics = circuitBreaker.metrics;\n            }\n            return this;\n        }\n\n        TestCommandBuilder setThreadPool(HystrixThreadPool threadPool) {\n            this.threadPool = threadPool;\n            return this;\n        }\n\n        TestCommandBuilder setCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) {\n            this.commandPropertiesDefaults = commandPropertiesDefaults;\n            return this;\n        }\n\n        TestCommandBuilder setThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {\n            this.threadPoolPropertiesDefaults = threadPoolPropertiesDefaults;\n            return this;\n        }\n\n        TestCommandBuilder setMetrics(HystrixCommandMetrics metrics) {\n            this.metrics = metrics;\n            return this;\n        }\n\n        TestCommandBuilder setFallbackSemaphore(AbstractCommand.TryableSemaphore fallbackSemaphore) {\n            this.fallbackSemaphore = fallbackSemaphore;\n            return this;\n        }\n\n        TestCommandBuilder setExecutionSemaphore(AbstractCommand.TryableSemaphore executionSemaphore) {\n            this.executionSemaphore = executionSemaphore;\n            return this;\n        }\n\n        TestCommandBuilder setExecutionHook(TestableExecutionHook executionHook) {\n            this.executionHook = executionHook;\n            return this;\n        }\n\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/NotWrappedByHystrixTestException.java",
    "content": "package com.netflix.hystrix;\n\nimport com.netflix.hystrix.exception.ExceptionNotWrappedByHystrix;\n\npublic class NotWrappedByHystrixTestException extends Exception implements ExceptionNotWrappedByHystrix {\n    private static final long serialVersionUID = 1L;\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/NotWrappedByHystrixTestRuntimeException.java",
    "content": "package com.netflix.hystrix;\n\nimport com.netflix.hystrix.exception.ExceptionNotWrappedByHystrix;\n\npublic class NotWrappedByHystrixTestRuntimeException extends RuntimeException implements ExceptionNotWrappedByHystrix {\n    private static final long serialVersionUID = 1L;\n\n    public NotWrappedByHystrixTestRuntimeException() {\n        super(\"Raw exception for TestHystrixCommand\");\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/TestHystrixCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\n\nabstract public class TestHystrixCommand<T> extends HystrixCommand<T> implements AbstractTestHystrixCommand<T> {\n\n    private final TestCommandBuilder builder;\n\n    public TestHystrixCommand(TestCommandBuilder builder) {\n        super(builder.owner, builder.dependencyKey, builder.threadPoolKey, builder.circuitBreaker, builder.threadPool,\n                builder.commandPropertiesDefaults, builder.threadPoolPropertiesDefaults, builder.metrics,\n                builder.fallbackSemaphore, builder.executionSemaphore, TEST_PROPERTIES_FACTORY, builder.executionHook);\n        this.builder = builder;\n    }\n\n    public TestHystrixCommand(TestCommandBuilder builder, HystrixCommandExecutionHook executionHook) {\n        super(builder.owner, builder.dependencyKey, builder.threadPoolKey, builder.circuitBreaker, builder.threadPool,\n                builder.commandPropertiesDefaults, builder.threadPoolPropertiesDefaults, builder.metrics,\n                builder.fallbackSemaphore, builder.executionSemaphore, TEST_PROPERTIES_FACTORY, executionHook);\n        this.builder = builder;\n    }\n\n    public TestCommandBuilder getBuilder() {\n        return builder;\n    }\n\n    static TestCommandBuilder testPropsBuilder() {\n        return new TestCommandBuilder(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);\n    }\n\n    static TestCommandBuilder testPropsBuilder(HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker) {\n        return new TestCommandBuilder(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD).setCircuitBreaker(circuitBreaker);\n    }\n\n    static TestCommandBuilder testPropsBuilder(HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy) {\n        return new TestCommandBuilder(isolationStrategy);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/TestHystrixObservableCommand.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nabstract public class TestHystrixObservableCommand<T> extends HystrixObservableCommand<T> implements AbstractTestHystrixCommand<T> {\n\n    private final TestCommandBuilder builder;\n\n    public TestHystrixObservableCommand(TestCommandBuilder builder) {\n        super(builder.owner, builder.dependencyKey, builder.threadPoolKey, builder.circuitBreaker, builder.threadPool,\n                builder.commandPropertiesDefaults, builder.threadPoolPropertiesDefaults, builder.metrics,\n                builder.fallbackSemaphore, builder.executionSemaphore, TEST_PROPERTIES_FACTORY, builder.executionHook);\n        this.builder = builder;\n    }\n\n    public TestCommandBuilder getBuilder() {\n        return builder;\n    }\n\n    static TestCommandBuilder testPropsBuilder() {\n        return new TestCommandBuilder(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n    }\n\n    static TestCommandBuilder testPropsBuilder(HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker) {\n        return new TestCommandBuilder(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE).setCircuitBreaker(circuitBreaker);\n    }\n\n    static TestCommandBuilder testPropsBuilder(HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy, HystrixCircuitBreakerTest.TestCircuitBreaker circuitBreaker) {\n        return new TestCommandBuilder(isolationStrategy).setCircuitBreaker(circuitBreaker);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/TestableExecutionHook.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.exception.HystrixRuntimeException.FailureType;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport rx.Notification;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nclass TestableExecutionHook extends HystrixCommandExecutionHook {\n\n    private static void recordHookCall(StringBuilder sequenceRecorder, String methodName) {\n        sequenceRecorder.append(methodName).append(\" - \");\n    }\n\n    StringBuilder executionSequence = new StringBuilder();\n    List<Notification<?>> commandEmissions = new ArrayList<Notification<?>>();\n    List<Notification<?>> executionEmissions = new ArrayList<Notification<?>>();\n    List<Notification<?>> fallbackEmissions = new ArrayList<Notification<?>>();\n\n    public boolean commandEmissionsMatch(int numOnNext, int numOnError, int numOnCompleted) {\n        return eventsMatch(commandEmissions, numOnNext, numOnError, numOnCompleted);\n    }\n\n    public boolean executionEventsMatch(int numOnNext, int numOnError, int numOnCompleted) {\n        return eventsMatch(executionEmissions, numOnNext, numOnError, numOnCompleted);\n    }\n\n    public boolean fallbackEventsMatch(int numOnNext, int numOnError, int numOnCompleted) {\n        return eventsMatch(fallbackEmissions, numOnNext, numOnError, numOnCompleted);\n    }\n\n    private boolean eventsMatch(List<Notification<?>> l, int numOnNext, int numOnError, int numOnCompleted) {\n        boolean matchFailed = false;\n        int actualOnNext = 0;\n        int actualOnError = 0;\n        int actualOnCompleted = 0;\n\n\n        if (l.size() != numOnNext + numOnError + numOnCompleted) {\n            System.out.println(\"Actual : \" + l + \", Expected : \" + numOnNext + \" OnNexts, \" + numOnError + \" OnErrors, \" + numOnCompleted + \" OnCompleted\");\n            return false;\n        }\n        for (int n = 0; n < numOnNext; n++) {\n            Notification<?> current = l.get(n);\n            if (!current.isOnNext()) {\n                matchFailed = true;\n            } else {\n                actualOnNext++;\n            }\n        }\n        for (int e = numOnNext; e < numOnNext + numOnError; e++) {\n            Notification<?> current = l.get(e);\n            if (!current.isOnError()) {\n                matchFailed = true;\n            } else {\n                actualOnError++;\n            }\n        }\n        for (int c = numOnNext + numOnError; c < numOnNext + numOnError + numOnCompleted; c++) {\n            Notification<?> current = l.get(c);\n            if (!current.isOnCompleted()) {\n                matchFailed = true;\n            } else {\n                actualOnCompleted++;\n            }\n        }\n        if (matchFailed) {\n            System.out.println(\"Expected : \" + numOnNext + \" OnNexts, \" + numOnError + \" OnErrors, and \" + numOnCompleted);\n            System.out.println(\"Actual : \" + actualOnNext + \" OnNexts, \" + actualOnError + \" OnErrors, and \" + actualOnCompleted);\n        }\n        return !matchFailed;\n    }\n\n    public Throwable getCommandException() {\n        return getException(commandEmissions);\n    }\n\n    public Throwable getExecutionException() {\n        return getException(executionEmissions);\n    }\n\n    public Throwable getFallbackException() {\n        return getException(fallbackEmissions);\n    }\n\n    private Throwable getException(List<Notification<?>> l) {\n        for (Notification<?> n: l) {\n            if (n.isOnError()) {\n                n.getThrowable().printStackTrace();\n                return n.getThrowable();\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public <T> void onStart(HystrixInvokable<T> commandInstance) {\n        super.onStart(commandInstance);\n        recordHookCall(executionSequence, \"onStart\");\n    }\n\n    @Override\n    public <T> T onEmit(HystrixInvokable<T> commandInstance, T value) {\n        commandEmissions.add(Notification.createOnNext(value));\n        recordHookCall(executionSequence, \"onEmit\");\n        return super.onEmit(commandInstance, value);\n    }\n\n    @Override\n    public <T> Exception onError(HystrixInvokable<T> commandInstance, FailureType failureType, Exception e) {\n        commandEmissions.add(Notification.createOnError(e));\n        recordHookCall(executionSequence, \"onError\");\n        return super.onError(commandInstance, failureType, e);\n    }\n\n    @Override\n    public <T> void onSuccess(HystrixInvokable<T> commandInstance) {\n        commandEmissions.add(Notification.createOnCompleted());\n        recordHookCall(executionSequence, \"onSuccess\");\n        super.onSuccess(commandInstance);\n    }\n\n    @Override\n    public <T> void onThreadStart(HystrixInvokable<T> commandInstance) {\n        super.onThreadStart(commandInstance);\n        recordHookCall(executionSequence, \"onThreadStart\");\n    }\n\n    @Override\n    public <T> void onThreadComplete(HystrixInvokable<T> commandInstance) {\n        super.onThreadComplete(commandInstance);\n        recordHookCall(executionSequence, \"onThreadComplete\");\n    }\n\n    @Override\n    public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {\n        recordHookCall(executionSequence, \"onExecutionStart\");\n        super.onExecutionStart(commandInstance);\n    }\n\n    @Override\n    public <T> T onExecutionEmit(HystrixInvokable<T> commandInstance, T value) {\n        executionEmissions.add(Notification.createOnNext(value));\n        recordHookCall(executionSequence, \"onExecutionEmit\");\n        return super.onExecutionEmit(commandInstance, value);\n    }\n\n    @Override\n    public <T> Exception onExecutionError(HystrixInvokable<T> commandInstance, Exception e) {\n        executionEmissions.add(Notification.createOnError(e));\n        recordHookCall(executionSequence, \"onExecutionError\");\n        return super.onExecutionError(commandInstance, e);\n    }\n\n    @Override\n    public <T> void onExecutionSuccess(HystrixInvokable<T> commandInstance) {\n        executionEmissions.add(Notification.createOnCompleted());\n        recordHookCall(executionSequence, \"onExecutionSuccess\");\n        super.onExecutionSuccess(commandInstance);\n    }\n\n    @Override\n    public <T> void onFallbackStart(HystrixInvokable<T> commandInstance) {\n        super.onFallbackStart(commandInstance);\n        recordHookCall(executionSequence, \"onFallbackStart\");\n    }\n\n    @Override\n    public <T> T onFallbackEmit(HystrixInvokable<T> commandInstance, T value) {\n        fallbackEmissions.add(Notification.createOnNext(value));\n        recordHookCall(executionSequence, \"onFallbackEmit\");\n        return super.onFallbackEmit(commandInstance, value);\n    }\n\n    @Override\n    public <T> Exception onFallbackError(HystrixInvokable<T> commandInstance, Exception e) {\n        fallbackEmissions.add(Notification.createOnError(e));\n        recordHookCall(executionSequence, \"onFallbackError\");\n        return super.onFallbackError(commandInstance, e);\n    }\n\n    @Override\n    public <T> void onFallbackSuccess(HystrixInvokable<T> commandInstance) {\n        fallbackEmissions.add(Notification.createOnCompleted());\n        recordHookCall(executionSequence, \"onFallbackSuccess\");\n        super.onFallbackSuccess(commandInstance);\n    }\n\n    @Override\n    public <T> void onCacheHit(HystrixInvokable<T> commandInstance) {\n        super.onCacheHit(commandInstance);\n        recordHookCall(executionSequence, \"onCacheHit\");\n    }\n\n    @Override\n    public <T> void onUnsubscribe(HystrixInvokable<T> commandInstance) {\n        super.onUnsubscribe(commandInstance);\n        recordHookCall(executionSequence, \"onUnsubscribe\");\n    }\n\n    /**\n     * DEPRECATED METHODS FOLLOW.  The string representation starts with `!` to distinguish\n     */\n\n    AtomicInteger startExecute = new AtomicInteger();\n    Object endExecuteSuccessResponse = null;\n    Exception endExecuteFailureException = null;\n    HystrixRuntimeException.FailureType endExecuteFailureType = null;\n    AtomicInteger startRun = new AtomicInteger();\n    Object runSuccessResponse = null;\n    Exception runFailureException = null;\n    AtomicInteger startFallback = new AtomicInteger();\n    Object fallbackSuccessResponse = null;\n    Exception fallbackFailureException = null;\n    AtomicInteger threadStart = new AtomicInteger();\n    AtomicInteger threadComplete = new AtomicInteger();\n    AtomicInteger cacheHit = new AtomicInteger();\n\n    @Override\n    public <T> T onFallbackSuccess(HystrixInvokable<T> commandInstance, T response) {\n        recordHookCall(executionSequence, \"!onFallbackSuccess\");\n        return super.onFallbackSuccess(commandInstance, response);\n    }\n\n    @Override\n    public <T> T onComplete(HystrixInvokable<T> commandInstance, T response) {\n        recordHookCall(executionSequence, \"!onComplete\");\n        return super.onComplete(commandInstance, response);\n    }\n\n    @Override\n    public <T> void onRunStart(HystrixInvokable<T> commandInstance) {\n        super.onRunStart(commandInstance);\n        recordHookCall(executionSequence, \"!onRunStart\");\n    }\n\n    @Override\n    public <T> T onRunSuccess(HystrixInvokable<T> commandInstance, T response) {\n        recordHookCall(executionSequence, \"!onRunSuccess\");\n        return super.onRunSuccess(commandInstance, response);\n    }\n\n    @Override\n    public <T> Exception onRunError(HystrixInvokable<T> commandInstance, Exception e) {\n        recordHookCall(executionSequence, \"!onRunError\");\n        return super.onRunError(commandInstance, e);\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/UnsubscribedTasksRequestCacheTest.java",
    "content": "/**\n * Copyright 2017 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.netflix.hystrix;\n\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.*;\n\npublic class UnsubscribedTasksRequestCacheTest {\n\n    private AtomicBoolean encounteredCommandException = new AtomicBoolean(false);\n    private AtomicInteger numOfExecutions = new AtomicInteger(0);\n\n    public class CommandExecutionHook extends HystrixCommandExecutionHook {\n\n        @Override\n        public <T> Exception onError(HystrixInvokable<T> commandInstance, HystrixRuntimeException.FailureType failureType, Exception e) {\n            e.printStackTrace();\n            encounteredCommandException.set(true);\n            return e;\n        }\n    }\n\n    public class CommandUsingRequestCache extends HystrixCommand<Boolean> {\n\n        private final int value;\n\n        protected CommandUsingRequestCache(int value) {\n            super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n            this.value = value;\n        }\n\n        @Override\n        protected Boolean run() {\n            numOfExecutions.getAndIncrement();\n            System.out.println(Thread.currentThread().getName() + \" run()\");\n            return value == 0 || value % 2 == 0;\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return String.valueOf(value);\n        }\n    }\n\n    @Before\n    public void init() {\n        HystrixPlugins.reset();\n    }\n\n    @After\n    public void reset() {\n        HystrixPlugins.reset();\n    }\n\n    @Test\n    public void testOneCommandIsUnsubscribed() throws ExecutionException, InterruptedException {\n\n        HystrixPlugins.getInstance().registerCommandExecutionHook(new CommandExecutionHook());\n        final HystrixRequestContext context = HystrixRequestContext.initializeContext();\n        final AtomicInteger numCacheResponses = new AtomicInteger(0);\n\n        try {\n            ExecutorService executorService = Executors.newSingleThreadExecutor();\n\n            Future futureCommand2a = executorService.submit(createCommandRunnable(context, numCacheResponses));\n            Future futureCommand2b = executorService.submit(createCommandRunnable(context, numCacheResponses));\n\n            futureCommand2a.get();\n            futureCommand2b.get();\n\n            assertEquals(1, numCacheResponses.get());\n            assertEquals(1, numOfExecutions.get());\n            assertFalse(encounteredCommandException.get());\n        } finally {\n            context.shutdown();\n        }\n    }\n\n    private Runnable createCommandRunnable(final HystrixRequestContext context, final AtomicInteger numCacheResponses) {\n        return new Runnable() {\n\n            public void run() {\n\n                HystrixRequestContext.setContextOnCurrentThread(context);\n\n                CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);\n                Future<Boolean> resultCommand2a = command2a.queue();\n\n                try {\n                    assertTrue(resultCommand2a.get());\n                    System.out.println(Thread.currentThread() + \" \" + command2a.isResponseFromCache());\n                    if (command2a.isResponseFromCache()) {\n                        numCacheResponses.getAndIncrement();\n                    }\n                } catch (Exception e) {\n                    fail(\"Exception: \" + e.getMessage());\n                }\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/collapser/CollapsedRequestSubjectTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.collapser;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport org.junit.Test;\n\nimport rx.Observable;\n\npublic class CollapsedRequestSubjectTest {\n    @Test\n    public void testSetResponseSuccess() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setResponse(\"theResponse\");\n\n        // fetch value\n        assertEquals(\"theResponse\", v.get());\n    }\n\n    @Test\n    public void testSetNullResponseSuccess() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setResponse(null);\n\n        // fetch value\n        assertEquals(null, v.get());\n    }\n\n    @Test\n    public void testSetException() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setException(new RuntimeException(\"anException\"));\n\n        // fetch value\n        try {\n            v.get();\n            fail(\"expected exception\");\n        } catch (ExecutionException e) {\n            assertEquals(\"anException\", e.getCause().getMessage());\n        }\n    }\n\n    @Test\n    public void testSetExceptionAfterResponse() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setResponse(\"theResponse\");\n\n        try {\n            cr.setException(new RuntimeException(\"anException\"));\n            fail(\"expected IllegalState\");\n        } catch (IllegalStateException e) {\n\n        }\n\n        assertEquals(\"theResponse\", v.get());\n    }\n\n    @Test\n    public void testSetResponseAfterException() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setException(new RuntimeException(\"anException\"));\n\n        try {\n            cr.setResponse(\"theResponse\");\n            fail(\"expected IllegalState\");\n        } catch (IllegalStateException e) {\n\n        }\n\n        try {\n            v.get();\n            fail(\"expected exception\");\n        } catch (ExecutionException e) {\n            assertEquals(\"anException\", e.getCause().getMessage());\n        }\n    }\n\n    @Test\n    public void testSetResponseDuplicate() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setResponse(\"theResponse\");\n\n        try {\n            cr.setResponse(\"theResponse2\");\n            fail(\"expected IllegalState\");\n        } catch (IllegalStateException e) {\n\n        }\n\n        assertEquals(\"theResponse\", v.get());\n    }\n\n    @Test(expected = CancellationException.class)\n    public void testSetResponseAfterUnsubscribe() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> f = o.toBlocking().toFuture();\n\n        // cancel/unsubscribe\n        f.cancel(true);\n\n        try {\n            cr.setResponse(\"theResponse\");\n        } catch (IllegalStateException e) {\n            fail(\"this should have done nothing as it was unsubscribed already\");\n        }\n\n        // expect CancellationException after cancelling\n        f.get();\n    }\n\n    @Test(expected = CancellationException.class)\n    public void testSetExceptionAfterUnsubscribe() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> f = o.toBlocking().toFuture();\n\n        // cancel/unsubscribe\n        f.cancel(true);\n\n        try {\n            cr.setException(new RuntimeException(\"anException\"));\n        } catch (IllegalStateException e) {\n            fail(\"this should have done nothing as it was unsubscribed already\");\n        }\n\n        // expect CancellationException after cancelling\n        f.get();\n    }\n\n    @Test\n    public void testUnsubscribeAfterSetResponse() throws InterruptedException, ExecutionException {\n        CollapsedRequestSubject<String, String> cr = new CollapsedRequestSubject<String, String>(\"hello\");\n        Observable<String> o = cr.toObservable();\n        Future<String> v = o.toBlocking().toFuture();\n\n        cr.setResponse(\"theResponse\");\n\n        // unsubscribe after the value is sent\n        v.cancel(true);\n\n        // still get value as it was set before canceling\n        assertEquals(\"theResponse\", v.get());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/config/HystrixConfigurationStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.config;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixConfigurationStream;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.schedulers.Schedulers;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\npublic class HystrixConfigurationStreamTest extends CommandStreamTest {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    HystrixConfigurationStream stream;\n    private final static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Config\");\n    private final static HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"Command\");\n\n    @Before\n    public void init() {\n        stream = HystrixConfigurationStream.getNonSingletonInstanceOnlyUsedInUnitTests(10);\n    }\n\n    @Test\n    public void testStreamHasData() throws Exception {\n        final AtomicBoolean commandShowsUp = new AtomicBoolean(false);\n        final AtomicBoolean threadPoolShowsUp = new AtomicBoolean(false);\n        final CountDownLatch latch = new CountDownLatch(1);\n        final int NUM = 10;\n\n        for (int i = 0; i < 2; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.observe();\n        }\n\n        stream.observe().take(NUM).subscribe(\n                new Subscriber<HystrixConfiguration>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnError : \" + e);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixConfiguration configuration) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Received data with : \" + configuration.getCommandConfig().size() + \" commands\");\n                        if (configuration.getCommandConfig().containsKey(commandKey)) {\n                            commandShowsUp.set(true);\n                        }\n                        if (!configuration.getThreadPoolConfig().isEmpty()) {\n                            threadPoolShowsUp.set(true);\n                        }\n                    }\n                });\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(commandShowsUp.get());\n        assertTrue(threadPoolShowsUp.get());\n    }\n\n    @Test\n    public void testTwoSubscribersOneUnsubscribes() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixConfiguration>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixConfiguration configuration) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + configuration);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixConfiguration>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixConfiguration configuration) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + configuration);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute 1 command, then unsubscribe from first stream. then execute the rest\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 1) {\n                s1.unsubscribe();\n            }\n        }\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n        assertTrue(\"s1 got less data than s2\", payloads2.get() > payloads1.get());\n    }\n\n    @Test\n    public void testTwoSubscribersBothUnsubscribe() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixConfiguration>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixConfiguration configuration) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + configuration);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixConfiguration>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixConfiguration configuration) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + configuration);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute 2 commands, then unsubscribe from both streams, then execute the rest\n        for (int i = 0; i < 10; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 2) {\n                s1.unsubscribe();\n                s2.unsubscribe();\n            }\n        }\n        assertFalse(stream.isSourceCurrentlySubscribed());  //both subscriptions have been cancelled - source should be too\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n    }\n\n    @Test\n    public void testTwoSubscribersOneSlowOneFast() throws Exception {\n        final CountDownLatch latch = new CountDownLatch(1);\n        final AtomicBoolean foundError = new AtomicBoolean(false);\n\n        Observable<HystrixConfiguration> fast = stream\n                .observe()\n                .observeOn(Schedulers.newThread());\n        Observable<HystrixConfiguration> slow = stream\n                .observe()\n                .observeOn(Schedulers.newThread())\n                .map(new Func1<HystrixConfiguration, HystrixConfiguration>() {\n                    @Override\n                    public HystrixConfiguration call(HystrixConfiguration config) {\n                        try {\n                            Thread.sleep(100);\n                            return config;\n                        } catch (InterruptedException ex) {\n                            return config;\n                        }\n                    }\n                });\n\n        Observable<Boolean> checkZippedEqual = Observable.zip(fast, slow, new Func2<HystrixConfiguration, HystrixConfiguration, Boolean>() {\n            @Override\n            public Boolean call(HystrixConfiguration payload, HystrixConfiguration payload2) {\n                return payload == payload2;\n            }\n        });\n\n        Subscription s1 = checkZippedEqual\n                .take(10000)\n                .subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + e);\n                        e.printStackTrace();\n                        foundError.set(true);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        //System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + b);\n                    }\n                });\n\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n        }\n\n        latch.await(10000, TimeUnit.MILLISECONDS);\n        assertFalse(foundError.get());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/CommandStreamTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserProperties;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\nimport com.netflix.hystrix.exception.HystrixBadRequestException;\nimport rx.functions.Func2;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic abstract class CommandStreamTest {\n\n    static final AtomicInteger uniqueId = new AtomicInteger(0);\n\n    public static class Command extends HystrixCommand<Integer> {\n\n        final String arg;\n\n        final HystrixEventType executionResult;\n        final int executionLatency;\n        final HystrixEventType fallbackExecutionResult;\n        final int fallbackExecutionLatency;\n\n        private Command(Setter setter, HystrixEventType executionResult, int executionLatency, String arg,\n                        HystrixEventType fallbackExecutionResult, int fallbackExecutionLatency) {\n            super(setter);\n            this.executionResult = executionResult;\n            this.executionLatency = executionLatency;\n            this.fallbackExecutionResult = fallbackExecutionResult;\n            this.fallbackExecutionLatency = fallbackExecutionLatency;\n            this.arg = arg;\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType) {\n            return from(groupKey, key, desiredEventType, 0);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency) {\n            return from(groupKey, key, desiredEventType, latency, HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency,\n                                      HystrixEventType desiredFallbackEventType) {\n            return from(groupKey, key, desiredEventType, latency, HystrixCommandProperties.ExecutionIsolationStrategy.THREAD, desiredFallbackEventType);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency,\n                                      HystrixEventType desiredFallbackEventType, int fallbackLatency) {\n            return from(groupKey, key, desiredEventType, latency, HystrixCommandProperties.ExecutionIsolationStrategy.THREAD, desiredFallbackEventType, fallbackLatency);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency,\n                                      HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy) {\n            return from(groupKey, key, desiredEventType, latency, isolationStrategy, HystrixEventType.FALLBACK_SUCCESS, 0);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency,\n                                      HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy,\n                                      HystrixEventType desiredFallbackEventType) {\n            return from(groupKey, key, desiredEventType, latency, isolationStrategy, desiredFallbackEventType, 0);\n        }\n\n        public static Command from(HystrixCommandGroupKey groupKey, HystrixCommandKey key, HystrixEventType desiredEventType, int latency,\n                                      HystrixCommandProperties.ExecutionIsolationStrategy isolationStrategy,\n                                      HystrixEventType desiredFallbackEventType, int fallbackLatency) {\n            Setter setter = Setter.withGroupKey(groupKey)\n                    .andCommandKey(key)\n                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                            .withExecutionTimeoutInMilliseconds(600)\n                            .withExecutionIsolationStrategy(isolationStrategy)\n                            .withCircuitBreakerEnabled(true)\n                            .withCircuitBreakerRequestVolumeThreshold(3)\n                            .withMetricsHealthSnapshotIntervalInMilliseconds(100)\n                            .withMetricsRollingStatisticalWindowInMilliseconds(1000)\n                            .withMetricsRollingStatisticalWindowBuckets(10)\n                            .withRequestCacheEnabled(true)\n                            .withRequestLogEnabled(true)\n                            .withFallbackIsolationSemaphoreMaxConcurrentRequests(5))\n                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(groupKey.name()))\n                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()\n                            .withCoreSize(10)\n                            .withMaxQueueSize(-1));\n\n            String uniqueArg;\n\n            switch (desiredEventType) {\n                case SUCCESS:\n                    uniqueArg = uniqueId.incrementAndGet() + \"\";\n                    return new Command(setter, HystrixEventType.SUCCESS, latency, uniqueArg, desiredFallbackEventType, 0);\n                case FAILURE:\n                    uniqueArg = uniqueId.incrementAndGet() + \"\";\n                    return new Command(setter, HystrixEventType.FAILURE, latency, uniqueArg, desiredFallbackEventType, fallbackLatency);\n                case TIMEOUT:\n                    uniqueArg = uniqueId.incrementAndGet() + \"\";\n                    return new Command(setter, HystrixEventType.SUCCESS, 700, uniqueArg, desiredFallbackEventType, fallbackLatency);\n                case BAD_REQUEST:\n                    uniqueArg = uniqueId.incrementAndGet() + \"\";\n                    return new Command(setter, HystrixEventType.BAD_REQUEST, latency, uniqueArg, desiredFallbackEventType, 0);\n                case RESPONSE_FROM_CACHE:\n                    String arg = uniqueId.get() + \"\";\n                    return new Command(setter, HystrixEventType.SUCCESS, 0, arg, desiredFallbackEventType, 0);\n                default:\n                    throw new RuntimeException(\"not supported yet\");\n            }\n        }\n\n        public static List<Command> getCommandsWithResponseFromCache(HystrixCommandGroupKey groupKey, HystrixCommandKey key) {\n            Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n            Command cmd2 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n            List<Command> cmds = new ArrayList<Command>();\n            cmds.add(cmd1);\n            cmds.add(cmd2);\n            return cmds;\n        }\n\n        @Override\n        protected Integer run() throws Exception {\n            try {\n                Thread.sleep(executionLatency);\n                switch (executionResult) {\n                    case SUCCESS:\n                        return 1;\n                    case FAILURE:\n                        throw new RuntimeException(\"induced failure\");\n                    case BAD_REQUEST:\n                        throw new HystrixBadRequestException(\"induced bad request\");\n                    default:\n                        throw new RuntimeException(\"unhandled HystrixEventType : \" + executionResult);\n                }\n            } catch (InterruptedException ex) {\n                System.out.println(\"Received InterruptedException : \" + ex);\n                throw ex;\n            }\n        }\n\n        @Override\n        protected Integer getFallback() {\n            try {\n                Thread.sleep(fallbackExecutionLatency);\n            } catch (InterruptedException ex) {\n                throw new RuntimeException(ex);\n            }\n            switch (fallbackExecutionResult) {\n                case FALLBACK_SUCCESS: return -1;\n                case FALLBACK_FAILURE: throw new RuntimeException(\"induced failure\");\n                case FALLBACK_MISSING: throw new UnsupportedOperationException(\"fallback not defined\");\n                default: throw new RuntimeException(\"unhandled HystrixEventType : \" + fallbackExecutionResult);\n            }\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return arg;\n        }\n    }\n\n    public static class Collapser extends HystrixCollapser<List<Integer>, Integer, Integer> {\n        private final Integer arg;\n\n        public static Collapser from(Integer arg) {\n            return new Collapser(HystrixCollapserKey.Factory.asKey(\"Collapser\"), arg);\n        }\n\n        public static Collapser from(HystrixCollapserKey key, Integer arg) {\n            return new Collapser(key, arg);\n        }\n\n        private Collapser(HystrixCollapserKey key, Integer arg) {\n            super(Setter.withCollapserKey(key)\n                    .andCollapserPropertiesDefaults(\n                            HystrixCollapserProperties.Setter()\n                    .withTimerDelayInMilliseconds(100)));\n            this.arg = arg;\n        }\n\n        @Override\n        public Integer getRequestArgument() {\n            return arg;\n        }\n\n        @Override\n        protected HystrixCommand<List<Integer>> createCommand(Collection<CollapsedRequest<Integer, Integer>> collapsedRequests) {\n            List<Integer> args = new ArrayList<Integer>();\n            for (CollapsedRequest<Integer, Integer> collapsedReq: collapsedRequests) {\n                args.add(collapsedReq.getArgument());\n            }\n            return new BatchCommand(args);\n        }\n\n        @Override\n        protected void mapResponseToRequests(List<Integer> batchResponse, Collection<CollapsedRequest<Integer, Integer>> collapsedRequests) {\n            for (CollapsedRequest<Integer, Integer> collapsedReq: collapsedRequests) {\n                collapsedReq.emitResponse(collapsedReq.getArgument());\n                collapsedReq.setComplete();\n            }\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return arg.toString();\n        }\n    }\n\n    private static class BatchCommand extends HystrixCommand<List<Integer>> {\n        private List<Integer> args;\n\n        protected BatchCommand(List<Integer> args) {\n            super(HystrixCommandGroupKey.Factory.asKey(\"BATCH\"));\n            this.args = args;\n        }\n\n        @Override\n        protected List<Integer> run() throws Exception {\n            System.out.println(Thread.currentThread().getName() + \" : Executing batch of : \" + args.size());\n            return args;\n        }\n    }\n\n    protected static String bucketToString(long[] eventCounts) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[\");\n        for (HystrixEventType eventType : HystrixEventType.values()) {\n            if (eventCounts[eventType.ordinal()] > 0) {\n                sb.append(eventType.name()).append(\"->\").append(eventCounts[eventType.ordinal()]).append(\", \");\n            }\n        }\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    protected static boolean hasData(long[] eventCounts) {\n        for (HystrixEventType eventType : HystrixEventType.values()) {\n            if (eventCounts[eventType.ordinal()] > 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/HystrixCommandCompletionStreamTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\npublic class HystrixCommandCompletionStreamTest {\n\n    private <T> Subscriber<T> getLatchedSubscriber(final CountDownLatch latch) {\n        return new Subscriber<T>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n                e.printStackTrace();\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(T value) {\n                System.out.println(\"OnNext : \" + value);\n            }\n        };\n    }\n\n    static final HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"COMMAND\");\n    static final HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool\");\n    final HystrixCommandCompletionStream commandStream = new HystrixCommandCompletionStream(commandKey);\n\n    @Test\n    public void noEvents() throws InterruptedException {\n        CountDownLatch latch = new CountDownLatch(1);\n        Subscriber<HystrixCommandCompletion> subscriber = getLatchedSubscriber(latch);\n\n        commandStream.observe().take(1).subscribe(subscriber);\n\n        //no writes\n\n        assertFalse(latch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSingleWriteSingleSubscriber() throws InterruptedException {\n        CountDownLatch latch = new CountDownLatch(1);\n        Subscriber<HystrixCommandCompletion> subscriber = getLatchedSubscriber(latch);\n\n        commandStream.observe().take(1).subscribe(subscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS).setExecutedInThread();\n        HystrixCommandCompletion event = HystrixCommandCompletion.from(result, commandKey, threadPoolKey);\n        commandStream.write(event);\n\n        assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSingleWriteMultipleSubscribers() throws InterruptedException {\n        CountDownLatch latch1 = new CountDownLatch(1);\n        Subscriber<HystrixCommandCompletion> subscriber1 = getLatchedSubscriber(latch1);\n\n        CountDownLatch latch2 = new CountDownLatch(1);\n        Subscriber<HystrixCommandCompletion> subscriber2 = getLatchedSubscriber(latch2);\n\n        commandStream.observe().take(1).subscribe(subscriber1);\n        commandStream.observe().take(1).subscribe(subscriber2);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS).setExecutedInThread();\n        HystrixCommandCompletion event = HystrixCommandCompletion.from(result, commandKey, threadPoolKey);\n        commandStream.write(event);\n\n        assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10, TimeUnit.MILLISECONDS));\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/HystrixThreadEventStreamTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport org.junit.Test;\nimport rx.Subscriber;\nimport rx.functions.Action1;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class HystrixThreadEventStreamTest {\n\n    HystrixCommandKey commandKey;\n    HystrixThreadPoolKey threadPoolKey;\n\n    HystrixThreadEventStream writeToStream;\n    HystrixCommandCompletionStream readCommandStream;\n    HystrixThreadPoolCompletionStream readThreadPoolStream;\n\n    public HystrixThreadEventStreamTest() {\n        commandKey = HystrixCommandKey.Factory.asKey(\"CMD-ThreadStream\");\n        threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"TP-ThreadStream\");\n\n        writeToStream = HystrixThreadEventStream.getInstance();\n        readCommandStream = HystrixCommandCompletionStream.getInstance(commandKey);\n        readThreadPoolStream = HystrixThreadPoolCompletionStream.getInstance(threadPoolKey);\n    }\n\n    private <T> Subscriber<T> getLatchedSubscriber(final CountDownLatch latch) {\n        return new Subscriber<T>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n                e.printStackTrace();\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(T value) {\n                System.out.println(\"OnNext : \" + value);\n            }\n        };\n    }\n\n    @Test\n    public void noEvents() throws InterruptedException {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        //no writes\n\n        assertFalse(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadIsolatedSuccess() throws InterruptedException {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS).setExecutedInThread();\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreIsolatedSuccess() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadIsolatedFailure() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.FAILURE).setExecutedInThread();\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreIsolatedFailure() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.FAILURE);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadIsolatedTimeout() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.TIMEOUT).setExecutedInThread();\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreIsolatedTimeout() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.TIMEOUT);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadIsolatedBadRequest() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.BAD_REQUEST).setExecutedInThread();\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreIsolatedBadRequest() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.BAD_REQUEST);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadRejectedCommand() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.THREAD_POOL_REJECTED);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreRejectedCommand() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SEMAPHORE_REJECTED);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testThreadIsolatedResponseFromCache() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<List<HystrixCommandCompletion>> commandListSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().buffer(500, TimeUnit.MILLISECONDS).take(1)\n                .doOnNext(new Action1<List<HystrixCommandCompletion>>() {\n                    @Override\n                    public void call(List<HystrixCommandCompletion> hystrixCommandCompletions) {\n                        System.out.println(\"LIST : \" + hystrixCommandCompletions);\n                        assertEquals(3, hystrixCommandCompletions.size());\n                    }\n                })\n                .subscribe(commandListSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS).setExecutedInThread();\n        ExecutionResult cache1 = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE);\n        ExecutionResult cache2 = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n        writeToStream.executionDone(cache1, commandKey, threadPoolKey);\n        writeToStream.executionDone(cache2, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertTrue(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testSemaphoreIsolatedResponseFromCache() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<List<HystrixCommandCompletion>> commandListSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().buffer(500, TimeUnit.MILLISECONDS).take(1)\n                .doOnNext(new Action1<List<HystrixCommandCompletion>>() {\n                    @Override\n                    public void call(List<HystrixCommandCompletion> hystrixCommandCompletions) {\n                        System.out.println(\"LIST : \" + hystrixCommandCompletions);\n                        assertEquals(3, hystrixCommandCompletions.size());\n                    }\n                })\n                .subscribe(commandListSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SUCCESS);\n        ExecutionResult cache1 = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE);\n        ExecutionResult cache2 = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n        writeToStream.executionDone(cache1, commandKey, threadPoolKey);\n        writeToStream.executionDone(cache2, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n\n    @Test\n    public void testShortCircuit() throws Exception {\n        CountDownLatch commandLatch = new CountDownLatch(1);\n        CountDownLatch threadPoolLatch = new CountDownLatch(1);\n\n        Subscriber<HystrixCommandCompletion> commandSubscriber = getLatchedSubscriber(commandLatch);\n        readCommandStream.observe().take(1).subscribe(commandSubscriber);\n\n        Subscriber<HystrixCommandCompletion> threadPoolSubscriber = getLatchedSubscriber(threadPoolLatch);\n        readThreadPoolStream.observe().take(1).subscribe(threadPoolSubscriber);\n\n        ExecutionResult result = ExecutionResult.from(HystrixEventType.SHORT_CIRCUITED);\n        writeToStream.executionDone(result, commandKey, threadPoolKey);\n\n        assertTrue(commandLatch.await(1000, TimeUnit.MILLISECONDS));\n        assertFalse(threadPoolLatch.await(1000, TimeUnit.MILLISECONDS));\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/CumulativeCollapserEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class CumulativeCollapserEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    CumulativeCollapserEventCounterStream stream;\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + collapserEventsToStr(eventCounts));\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        CumulativeCollapserEventCounterStream.reset();\n    }\n\n    protected static String collapserEventsToStr(long[] eventCounts) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[\");\n        for (HystrixEventType.Collapser eventType : HystrixEventType.Collapser.values()) {\n            if (eventCounts[eventType.ordinal()] > 0) {\n                sb.append(eventType.name()).append(\"->\").append(eventCounts[eventType.ordinal()]).append(\", \");\n            }\n        }\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"CumulativeCollapser-A\");\n        stream = CumulativeCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.ADDED_TO_BATCH));\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.BATCH_EXECUTED));\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.RESPONSE_FROM_CACHE));\n    }\n\n\n    @Test\n    public void testCollapsed() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"CumulativeCollapser-B\");\n        stream = CumulativeCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 1;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 3;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testCollapsedAndResponseFromCache() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"CumulativeCollapser-C\");\n        stream = CumulativeCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 1;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 3;\n        expected[HystrixEventType.Collapser.RESPONSE_FROM_CACHE.ordinal()] = 6;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    //by doing a take(30), we expect all values to stay in the stream, as cumulative counters never age out of window\n    @Test\n    public void testCollapsedAndResponseFromCacheAgeOutOfCumulativeWindow() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"CumulativeCollapser-D\");\n        stream = CumulativeCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 1;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 3;\n        expected[HystrixEventType.Collapser.RESPONSE_FROM_CACHE.ordinal()] = 6;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/CumulativeCommandEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class CumulativeCommandEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    CumulativeCommandEventCounterStream stream;\n\n    private static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"CumulativeCommandCounter\");\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + bucketToString(eventCounts));\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        CumulativeCommandEventCounterStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-A\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        assertFalse(hasData(stream.getLatest()));\n    }\n\n    @Test\n    public void testSingleSuccess() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-B\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-C\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleTimeout() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-D\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.TIMEOUT);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.TIMEOUT.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleBadRequest() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-E\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.BAD_REQUEST);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.BAD_REQUEST.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testRequestFromCache() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-F\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        expected[HystrixEventType.RESPONSE_FROM_CACHE.ordinal()] = 2;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testShortCircuited() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-G\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //3 failures in a row will trip circuit.  let bucket roll once then submit 2 requests.\n        //should see 3 FAILUREs and 2 SHORT_CIRCUITs and then 5 FALLBACK_SUCCESSes\n\n        Command failure1 = Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        Command failure2 = Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        Command failure3 = Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        Command shortCircuit1 = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n        Command shortCircuit2 = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        failure1.observe();\n        failure2.observe();\n        failure3.observe();\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        shortCircuit1.observe();\n        shortCircuit2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(shortCircuit1.isResponseShortCircuited());\n        assertTrue(shortCircuit2.isResponseShortCircuited());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 3;\n        expected[HystrixEventType.SHORT_CIRCUITED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 5;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSemaphoreRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-H\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate semaphore when called from different threads.\n        //submit 2 more requests and they should be SEMAPHORE_REJECTED\n        //should see 10 SUCCESSes, 2 SEMAPHORE_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<Command> saturators = new ArrayList<Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 500, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        Command rejected1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        Command rejected2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        for (final Command saturator : saturators) {\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturator.observe();\n                }\n            })).start();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseSemaphoreRejected());\n        assertTrue(rejected2.isResponseSemaphoreRejected());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 10;\n        expected[HystrixEventType.SEMAPHORE_REJECTED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 2;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testThreadPoolRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-I\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate threadpools when called concurrently.\n        //submit 2 more requests and they should be THREADPOOL_REJECTED\n        //should see 10 SUCCESSes, 2 THREADPOOL_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<Command> saturators = new ArrayList<Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 500));\n        }\n\n        Command rejected1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n        Command rejected2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n\n        for (final Command saturator : saturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseThreadPoolRejected());\n        assertTrue(rejected2.isResponseThreadPoolRejected());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 10;\n        expected[HystrixEventType.THREAD_POOL_REJECTED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 2;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-J\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_FAILURE);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackMissing() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-K\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd = Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_MISSING);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_MISSING.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackRejection() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-L\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //fallback semaphore size is 5.  So let 5 commands saturate that semaphore, then\n        //let 2 more commands go to fallback.  they should get rejected by the fallback-semaphore\n\n        List<Command> fallbackSaturators = new ArrayList<Command>();\n        for (int i = 0; i < 5; i++) {\n            fallbackSaturators.add(Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 400));\n        }\n\n        Command rejection1 = Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n        Command rejection2 = Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n\n        for (Command saturator: fallbackSaturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(70);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        rejection1.observe();\n        rejection2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 7;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 5;\n        expected[HystrixEventType.FALLBACK_REJECTION.ordinal()] = 2;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 2;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testCancelled() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-M\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command toCancel = Command.from(groupKey, key, HystrixEventType.SUCCESS, 500);\n\n        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : about to observe and subscribe\");\n        Subscription s = toCancel.observe().\n                doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : UnSubscribe from command.observe()\");\n                    }\n                }).\n                subscribe(new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(\"Command OnCompleted\");\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(\"Command OnError : \" + e);\n            }\n\n            @Override\n            public void onNext(Integer i) {\n                System.out.println(\"Command OnNext : \" + i);\n            }\n        });\n\n        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : about to unsubscribe\");\n        s.unsubscribe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.CANCELLED.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testCollapsed() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"BatchCommand\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(i).observe();\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        expected[HystrixEventType.COLLAPSED.ordinal()] = 3;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testMultipleEventsOverTimeGetStoredAndNeverAgeOut() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-CumulativeCounter-N\");\n        stream = CumulativeCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //by doing a take(30), we ensure that no rolling out of window takes place\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.FAILURE, 10);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/CumulativeThreadPoolEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class CumulativeThreadPoolEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    CumulativeThreadPoolEventCounterStream stream;\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + eventCounts[0] + \" : \" + eventCounts[1]);\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandEventCounterStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-A\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-A\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-A\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleSuccess() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-B\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-B\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-B\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleFailure() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-C\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-C\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-C\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleTimeout() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-D\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-D\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-D\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.TIMEOUT);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleBadRequest() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-E\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-E\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-E\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.BAD_REQUEST);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testRequestFromCache() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-F\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-F\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-F\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        CommandStreamTest.Command cmd3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n        //RESPONSE_FROM_CACHE should not show up at all in thread pool counters - just the success\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testShortCircuited() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-G\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-G\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-G\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //3 failures in a row will trip circuit.  let bucket roll once then submit 2 requests.\n        //should see 3 FAILUREs and 2 SHORT_CIRCUITs and each should see a FALLBACK_SUCCESS\n\n        CommandStreamTest.Command failure1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        CommandStreamTest.Command shortCircuit1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n        CommandStreamTest.Command shortCircuit2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        failure1.observe();\n        failure2.observe();\n        failure3.observe();\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        shortCircuit1.observe();\n        shortCircuit2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(shortCircuit1.isResponseShortCircuited());\n        assertTrue(shortCircuit2.isResponseShortCircuited());\n\n        //only the FAILUREs should show up in thread pool counters\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(3, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSemaphoreRejected() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-H\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-H\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-H\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate semaphore when called from different threads.\n        //submit 2 more requests and they should be SEMAPHORE_REJECTED\n        //should see 10 SUCCESSes, 2 SEMAPHORE_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<Command> saturators = new ArrayList<Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 300, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturator.observe();\n                }\n            })).start();\n        }\n\n        try {\n            Thread.sleep(10);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseSemaphoreRejected());\n        assertTrue(rejected2.isResponseSemaphoreRejected());\n\n        //none of these got executed on a thread-pool, so thread pool metrics should be 0\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testThreadPoolRejected() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-I\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-I\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-I\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate threadpools when called concurrently.\n        //submit 2 more requests and they should be THREADPOOL_REJECTED\n        //should see 10 SUCCESSes, 2 THREADPOOL_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<CommandStreamTest.Command> saturators = new ArrayList<CommandStreamTest.Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 700));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseThreadPoolRejected());\n        assertTrue(rejected2.isResponseThreadPoolRejected());\n\n        //all 12 commands got submitted to thread pool, 10 accepted, 2 rejected is expected\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(10, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(2, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-J\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-J\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-J\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_FAILURE);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackMissing() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-K\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-K\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-K\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_MISSING);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackRejection() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-L\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-L\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-L\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //fallback semaphore size is 5.  So let 5 commands saturate that semaphore, then\n        //let 2 more commands go to fallback.  they should get rejected by the fallback-semaphore\n\n        List<CommandStreamTest.Command> fallbackSaturators = new ArrayList<CommandStreamTest.Command>();\n        for (int i = 0; i < 5; i++) {\n            fallbackSaturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 400));\n        }\n\n        CommandStreamTest.Command rejection1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n        CommandStreamTest.Command rejection2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n\n        for (CommandStreamTest.Command saturator: fallbackSaturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(70);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        rejection1.observe();\n        rejection2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        //all 7 commands executed on-thread, so should be executed according to thread-pool metrics\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(7, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    //in a rolling window, take(30) would age out all counters.  in the cumulative count, we expect them to remain non-zero forever\n    @Test\n    public void testMultipleEventsOverTimeGetStoredAndDoNotAgeOut() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Cumulative-ThreadPool-M\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"Cumulative-ThreadPool-M\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"Cumulative-Counter-M\");\n        stream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 10);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        //all commands should have aged out\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(2, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/HealthCountsStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Func2;\nimport rx.schedulers.Schedulers;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.*;\n\npublic class HealthCountsStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    HealthCountsStream stream;\n\n    static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"HealthCounts\");\n\n    private static Subscriber<HystrixCommandMetrics.HealthCounts> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<HystrixCommandMetrics.HealthCounts>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(HystrixCommandMetrics.HealthCounts healthCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + healthCounts);\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandEventCounterStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-A\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0L, stream.getLatest().getErrorCount());\n        assertEquals(0L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSingleSuccess() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-B\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSingleFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-C\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSingleTimeout() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-D\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.TIMEOUT);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSingleBadRequest() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-E\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.BAD_REQUEST);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0L, stream.getLatest().getErrorCount());\n        assertEquals(0L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testRequestFromCache() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-F\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        CommandStreamTest.Command cmd3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests()); //responses from cache should not show up here\n    }\n\n    @Test\n    public void testShortCircuited() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-G\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //3 failures in a row will trip circuit.  let bucket roll once then submit 2 requests.\n        //should see 3 FAILUREs and 2 SHORT_CIRCUITs and then 5 FALLBACK_SUCCESSes\n\n        CommandStreamTest.Command failure1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        CommandStreamTest.Command shortCircuit1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n        CommandStreamTest.Command shortCircuit2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        failure1.observe();\n        failure2.observe();\n        failure3.observe();\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        shortCircuit1.observe();\n        shortCircuit2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        assertTrue(shortCircuit1.isResponseShortCircuited());\n        assertTrue(shortCircuit2.isResponseShortCircuited());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        //should only see failures here, not SHORT-CIRCUITS\n        assertEquals(3L, stream.getLatest().getErrorCount());\n        assertEquals(3L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSemaphoreRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-H\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate semaphore when called from different threads.\n        //submit 2 more requests and they should be SEMAPHORE_REJECTED\n        //should see 10 SUCCESSes, 2 SEMAPHORE_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<Command> saturators = new ArrayList<Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 400, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturator.observe();\n                }\n            })).start();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseSemaphoreRejected());\n        assertTrue(rejected2.isResponseSemaphoreRejected());\n        assertEquals(2L, stream.getLatest().getErrorCount());\n        assertEquals(12L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testThreadPoolRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-I\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate threadpools when called concurrently.\n        //submit 2 more requests and they should be THREADPOOL_REJECTED\n        //should see 10 SUCCESSes, 2 THREADPOOL_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<CommandStreamTest.Command> saturators = new ArrayList<CommandStreamTest.Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 400));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseThreadPoolRejected());\n        assertTrue(rejected2.isResponseThreadPoolRejected());\n        assertEquals(2L, stream.getLatest().getErrorCount());\n        assertEquals(12L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-J\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_FAILURE);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testFallbackMissing() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-K\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_MISSING);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(1L, stream.getLatest().getErrorCount());\n        assertEquals(1L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testFallbackRejection() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-L\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //fallback semaphore size is 5.  So let 5 commands saturate that semaphore, then\n        //let 2 more commands go to fallback.  they should get rejected by the fallback-semaphore\n\n        List<CommandStreamTest.Command> fallbackSaturators = new ArrayList<CommandStreamTest.Command>();\n        for (int i = 0; i < 5; i++) {\n            fallbackSaturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 400));\n        }\n\n        CommandStreamTest.Command rejection1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n        CommandStreamTest.Command rejection2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n\n        for (CommandStreamTest.Command saturator: fallbackSaturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(70);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        rejection1.observe();\n        rejection2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(7L, stream.getLatest().getErrorCount());\n        assertEquals(7L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testMultipleEventsOverTimeGetStoredAndAgeOut() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-M\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        //by doing a take(30), we ensure that all rolling counts go back to 0\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 10);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(0L, stream.getLatest().getErrorCount());\n        assertEquals(0L, stream.getLatest().getTotalRequests());\n    }\n\n    @Test\n    public void testSharedSourceStream() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-N\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        final AtomicBoolean allEqual = new AtomicBoolean(false);\n\n        Observable<HystrixCommandMetrics.HealthCounts> o1 = stream\n                .observe()\n                .take(10)\n                .observeOn(Schedulers.computation());\n\n        Observable<HystrixCommandMetrics.HealthCounts> o2 = stream\n                .observe()\n                .take(10)\n                .observeOn(Schedulers.computation());\n\n        Observable<Boolean> zipped = Observable.zip(o1, o2, new Func2<HystrixCommandMetrics.HealthCounts, HystrixCommandMetrics.HealthCounts, Boolean>() {\n            @Override\n            public Boolean call(HystrixCommandMetrics.HealthCounts healthCounts, HystrixCommandMetrics.HealthCounts healthCounts2) {\n                return healthCounts == healthCounts2;  //we want object equality\n            }\n        });\n        Observable < Boolean > reduced = zipped.reduce(true, new Func2<Boolean, Boolean, Boolean>() {\n            @Override\n            public Boolean call(Boolean a, Boolean b) {\n                return a && b;\n            }\n        });\n\n        reduced.subscribe(new Subscriber<Boolean>() {\n            @Override\n            public void onCompleted() {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Reduced OnCompleted\");\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Reduced OnError : \" + e);\n                e.printStackTrace();\n                latch.countDown();\n            }\n\n            @Override\n            public void onNext(Boolean b) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Reduced OnNext : \" + b);\n                allEqual.set(b);\n            }\n        });\n\n        for (int i = 0; i < 10; i++) {\n            HystrixCommand<Integer> cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n            cmd.execute();\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(allEqual.get());\n        //we should be getting the same object from both streams.  this ensures that multiple subscribers don't induce extra work\n    }\n\n    @Test\n    public void testTwoSubscribersOneUnsubscribes() throws Exception {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Health-O\");\n        stream = HealthCountsStream.getInstance(key, 10, 100);\n\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger healthCounts1 = new AtomicInteger(0);\n        final AtomicInteger healthCounts2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(10)\n                .observeOn(Schedulers.computation())\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixCommandMetrics.HealthCounts>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixCommandMetrics.HealthCounts healthCounts) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 1 OnNext : \" + healthCounts);\n                        healthCounts1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(10)\n                .observeOn(Schedulers.computation())\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixCommandMetrics.HealthCounts>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixCommandMetrics.HealthCounts healthCounts) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Health 2 OnNext : \" + healthCounts + \" : \" + healthCounts2.get());\n                        healthCounts2.incrementAndGet();\n                    }\n                });\n        //execute 5 commands, then unsubscribe from first stream. then execute the rest\n        for (int i = 0; i < 10; i++) {\n            HystrixCommand<Integer> cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n            cmd.execute();\n            if (i == 5) {\n                s1.unsubscribe();\n            }\n        }\n        assertTrue(stream.isSourceCurrentlySubscribed());  //only 1/2 subscriptions has been cancelled\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + healthCounts1.get() + \", s2 got : \" + healthCounts2.get());\n        assertTrue(\"s1 got data\", healthCounts1.get() > 0);\n        assertTrue(\"s2 got data\", healthCounts2.get() > 0);\n        assertTrue(\"s1 got less data than s2\", healthCounts2.get() > healthCounts1.get());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/HystrixDashboardStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.schedulers.Schedulers;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\npublic class HystrixDashboardStreamTest extends CommandStreamTest {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    HystrixDashboardStream stream;\n    private final static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Dashboard\");\n    private final static HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"DashboardCommand\");\n\n    @Before\n    public void init() {\n        stream = HystrixDashboardStream.getNonSingletonInstanceOnlyUsedInUnitTests(10);\n    }\n\n    @Test\n    public void testStreamHasData() throws Exception {\n        final AtomicBoolean commandShowsUp = new AtomicBoolean(false);\n        final CountDownLatch latch = new CountDownLatch(1);\n        final int NUM = 10;\n\n        for (int i = 0; i < 2; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.observe();\n        }\n\n        stream.observe().take(NUM).subscribe(\n                new Subscriber<HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnError : \" + e);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixDashboardStream.DashboardData dashboardData) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Received data with : \" + dashboardData.commandMetrics.size() + \" commands\");\n                        for (HystrixCommandMetrics metrics : dashboardData.commandMetrics) {\n                            if (metrics.getCommandKey().equals(commandKey)) {\n                                commandShowsUp.set(true);\n                            }\n                        }\n                    }\n                });\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(commandShowsUp.get());\n    }\n\n    @Test\n    public void testTwoSubscribersOneUnsubscribes() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixDashboardStream.DashboardData dashboardData) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + dashboardData);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixDashboardStream.DashboardData dashboardData) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + dashboardData);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute 1 command, then unsubscribe from first stream. then execute the rest\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 1) {\n                s1.unsubscribe();\n            }\n        }\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n        assertTrue(\"s1 got less data than s2\", payloads2.get() > payloads1.get());\n    }\n\n    @Test\n    public void testTwoSubscribersBothUnsubscribe() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(10)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixDashboardStream.DashboardData dashboardData) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + dashboardData);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(10)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixDashboardStream.DashboardData dashboardData) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + dashboardData);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute half the commands, then unsubscribe from both streams, then execute the rest\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 25) {\n                s1.unsubscribe();\n                s2.unsubscribe();\n            }\n        }\n        assertFalse(stream.isSourceCurrentlySubscribed());  //both subscriptions have been cancelled - source should be too\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n    }\n\n    @Test\n    public void testTwoSubscribersOneSlowOneFast() throws Exception {\n        final CountDownLatch latch = new CountDownLatch(1);\n        final AtomicBoolean foundError = new AtomicBoolean(false);\n\n        Observable<HystrixDashboardStream.DashboardData> fast = stream\n                .observe()\n                .observeOn(Schedulers.newThread());\n        Observable<HystrixDashboardStream.DashboardData> slow = stream\n                .observe()\n                .observeOn(Schedulers.newThread())\n                .map(new Func1<HystrixDashboardStream.DashboardData, HystrixDashboardStream.DashboardData>() {\n                    @Override\n                    public HystrixDashboardStream.DashboardData call(HystrixDashboardStream.DashboardData n) {\n                        try {\n                            Thread.sleep(100);\n                            return n;\n                        } catch (InterruptedException ex) {\n                            return n;\n                        }\n                    }\n                });\n\n        Observable<Boolean> checkZippedEqual = Observable.zip(fast, slow, new Func2<HystrixDashboardStream.DashboardData, HystrixDashboardStream.DashboardData, Boolean>() {\n            @Override\n            public Boolean call(HystrixDashboardStream.DashboardData payload, HystrixDashboardStream.DashboardData payload2) {\n                return payload == payload2;\n            }\n        });\n\n        Subscription s1 = checkZippedEqual\n                .take(10000)\n                .subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + e);\n                        e.printStackTrace();\n                        foundError.set(true);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        //System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + b);\n                    }\n                });\n\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n        }\n\n        latch.await(10000, TimeUnit.MILLISECONDS);\n        assertFalse(foundError.get());\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingCollapserBatchSizeDistributionStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.metric.CachedValuesHistogram;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\npublic class RollingCollapserBatchSizeDistributionStreamTest extends CommandStreamTest {\n    RollingCollapserBatchSizeDistributionStream stream;\n    HystrixRequestContext context;\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        stream.unsubscribe();\n        context.shutdown();\n        RollingCollapserBatchSizeDistributionStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesEmptyDistributions() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"Collapser-Batch-Size-A\");\n        stream = RollingCollapserBatchSizeDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().skip(10).take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis());\n                assertEquals(0, distribution.getTotalCount());\n            }\n        });\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(0, stream.getLatest().getTotalCount());\n    }\n\n    @Test\n    public void testBatches() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"Collapser-Batch-Size-B\");\n        stream = RollingCollapserBatchSizeDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis());\n            }\n        });\n\n        Collapser.from(key, 1).observe();\n        Collapser.from(key, 2).observe();\n        Collapser.from(key, 3).observe();\n\n        try {\n            Thread.sleep(250);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 4).observe();\n\n        try {\n            Thread.sleep(250);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 5).observe();\n        Collapser.from(key, 6).observe();\n        Collapser.from(key, 7).observe();\n        Collapser.from(key, 8).observe();\n        Collapser.from(key, 9).observe();\n\n        try {\n            Thread.sleep(250);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 10).observe();\n        Collapser.from(key, 11).observe();\n        Collapser.from(key, 12).observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        //should have 4 batches: 3, 1, 5, 3\n        assertEquals(4, stream.getLatest().getTotalCount());\n        assertEquals(3, stream.getLatestMean());\n        assertEquals(1, stream.getLatestPercentile(0));\n        assertEquals(5, stream.getLatestPercentile(100));\n    }\n\n    //by doing a take(30), all metrics should fall out of window and we should observe an empty histogram\n    @Test\n    public void testBatchesAgeOut() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"Collapser-Batch-Size-B\");\n        stream = RollingCollapserBatchSizeDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis());\n            }\n        });\n\n        Collapser.from(key, 1).observe();\n        Collapser.from(key, 2).observe();\n        Collapser.from(key, 3).observe();\n\n        try {\n            Thread.sleep(200);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 4).observe();\n\n        try {\n            Thread.sleep(200);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 5).observe();\n        Collapser.from(key, 6).observe();\n        Collapser.from(key, 7).observe();\n        Collapser.from(key, 8).observe();\n        Collapser.from(key, 9).observe();\n\n        try {\n            Thread.sleep(200);\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        Collapser.from(key, 10).observe();\n        Collapser.from(key, 11).observe();\n        Collapser.from(key, 12).observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        assertEquals(0, stream.getLatest().getTotalCount());\n        assertEquals(0, stream.getLatestMean());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingCollapserEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingCollapserEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    RollingCollapserEventCounterStream stream;\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + collapserEventsToStr(eventCounts));\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCollapserEventCounterStream.reset();\n    }\n\n    protected static String collapserEventsToStr(long[] eventCounts) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[\");\n        for (HystrixEventType.Collapser eventType : HystrixEventType.Collapser.values()) {\n            if (eventCounts[eventType.ordinal()] > 0) {\n                sb.append(eventType.name()).append(\"->\").append(eventCounts[eventType.ordinal()]).append(\", \");\n            }\n        }\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"RollingCollapser-A\");\n        stream = RollingCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.ADDED_TO_BATCH));\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.BATCH_EXECUTED));\n        assertEquals(0, stream.getLatest(HystrixEventType.Collapser.RESPONSE_FROM_CACHE));\n    }\n\n\n    @Test\n    public void testCollapsed() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"RollingCollapser-B\");\n        stream = RollingCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 1;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 3;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testCollapsedAndResponseFromCache() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"RollingCollapser-C\");\n        stream = RollingCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 1;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 3;\n        expected[HystrixEventType.Collapser.RESPONSE_FROM_CACHE.ordinal()] = 6;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    //by doing a take(30), we expect all values to return to 0 as they age out of rolling window\n    @Test\n    public void testCollapsedAndResponseFromCacheAgeOutOfRollingWindow() {\n        HystrixCollapserKey key = HystrixCollapserKey.Factory.asKey(\"RollingCollapser-D\");\n        stream = RollingCollapserEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(key, i).observe();\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n            CommandStreamTest.Collapser.from(key, i).observe(); //same arg - should get a response from cache\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.Collapser.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.Collapser.values().length];\n        expected[HystrixEventType.Collapser.BATCH_EXECUTED.ordinal()] = 0;\n        expected[HystrixEventType.Collapser.ADDED_TO_BATCH.ordinal()] = 0;\n        expected[HystrixEventType.Collapser.RESPONSE_FROM_CACHE.ordinal()] = 0;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingCommandEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingCommandEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    RollingCommandEventCounterStream stream;\n\n    static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"RollingCommandCounter\");\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + bucketToString(eventCounts));\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandEventCounterStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-A\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        assertFalse(hasData(stream.getLatest()));\n    }\n\n    @Test\n    public void testSingleSuccess() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-B\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-C\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 1;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleTimeout() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-D\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.TIMEOUT);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.TIMEOUT.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 1;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSingleBadRequest() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-E\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.BAD_REQUEST);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.BAD_REQUEST.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testRequestFromCache() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-F\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        CommandStreamTest.Command cmd3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        expected[HystrixEventType.RESPONSE_FROM_CACHE.ordinal()] = 2;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testShortCircuited() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-G\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //3 failures in a row will trip circuit.  let bucket roll once then submit 2 requests.\n        //should see 3 FAILUREs and 2 SHORT_CIRCUITs and then 5 FALLBACK_SUCCESSes\n\n        CommandStreamTest.Command failure1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        CommandStreamTest.Command shortCircuit1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n        CommandStreamTest.Command shortCircuit2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        failure1.observe();\n        failure2.observe();\n        failure3.observe();\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        shortCircuit1.observe();\n        shortCircuit2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(shortCircuit1.isResponseShortCircuited());\n        assertTrue(shortCircuit2.isResponseShortCircuited());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 3;\n        expected[HystrixEventType.SHORT_CIRCUITED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 5;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testSemaphoreRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-H\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate semaphore when called from different threads.\n        //submit 2 more requests and they should be SEMAPHORE_REJECTED\n        //should see 10 SUCCESSes, 2 SEMAPHORE_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<CommandStreamTest.Command> saturators = new ArrayList<CommandStreamTest.Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 200, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturator.observe();\n                }\n            })).start();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseSemaphoreRejected());\n        assertTrue(rejected2.isResponseSemaphoreRejected());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 10;\n        expected[HystrixEventType.SEMAPHORE_REJECTED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 2;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testThreadPoolRejected() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-I\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate threadpools when called concurrently.\n        //submit 2 more requests and they should be THREADPOOL_REJECTED\n        //should see 10 SUCCESSes, 2 THREADPOOL_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<CommandStreamTest.Command> saturators = new ArrayList<CommandStreamTest.Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 200));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseThreadPoolRejected());\n        assertTrue(rejected2.isResponseThreadPoolRejected());\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 10;\n        expected[HystrixEventType.THREAD_POOL_REJECTED.ordinal()] = 2;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 2;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-J\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_FAILURE);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackMissing() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-K\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_MISSING);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 1;\n        expected[HystrixEventType.FALLBACK_MISSING.ordinal()] = 1;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 1;\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testFallbackRejection() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-L\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //fallback semaphore size is 5.  So let 5 commands saturate that semaphore, then\n        //let 2 more commands go to fallback.  they should get rejected by the fallback-semaphore\n\n        List<CommandStreamTest.Command> fallbackSaturators = new ArrayList<CommandStreamTest.Command>();\n        for (int i = 0; i < 5; i++) {\n            fallbackSaturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 400));\n        }\n\n        CommandStreamTest.Command rejection1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n        CommandStreamTest.Command rejection2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n\n        for (CommandStreamTest.Command saturator: fallbackSaturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(70);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        rejection1.observe();\n        rejection2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.FAILURE.ordinal()] = 7;\n        expected[HystrixEventType.FALLBACK_SUCCESS.ordinal()] = 5;\n        expected[HystrixEventType.FALLBACK_REJECTION.ordinal()] = 2;\n        expected[HystrixEventType.EXCEPTION_THROWN.ordinal()] = 2;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testCollapsed() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"BatchCommand\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        for (int i = 0; i < 3; i++) {\n            CommandStreamTest.Collapser.from(i).observe();\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        expected[HystrixEventType.SUCCESS.ordinal()] = 1;\n        expected[HystrixEventType.COLLAPSED.ordinal()] = 3;\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n\n    @Test\n    public void testMultipleEventsOverTimeGetStoredAndAgeOut() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-RollingCounter-M\");\n        stream = RollingCommandEventCounterStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //by doing a take(30), we ensure that all rolling counts go back to 0\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 10);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(HystrixEventType.values().length, stream.getLatest().length);\n        long[] expected = new long[HystrixEventType.values().length];\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertArrayEquals(expected, stream.getLatest());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingCommandLatencyDistributionStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CachedValuesHistogram;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingCommandLatencyDistributionStreamTest extends CommandStreamTest {\n    RollingCommandLatencyDistributionStream stream;\n    HystrixRequestContext context;\n    static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"CommandLatency\");\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        stream.unsubscribe();\n        context.shutdown();\n        RollingCommandLatencyDistributionStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesEmptyDistributions() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-A\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis());\n                assertEquals(0, distribution.getTotalCount());\n            }\n        });\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(0, stream.getLatest().getTotalCount());\n    }\n\n    private void assertBetween(int expectedLow, int expectedHigh, int value) {\n        assertTrue(\"value too low (\" + value + \"), expected low = \" + expectedLow, expectedLow <= value);\n        assertTrue(\"value too high (\" + value + \"), expected high = \" + expectedHigh, expectedHigh >= value);\n    }\n\n    @Test\n    public void testSingleBucketGetsStored() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-B\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                if (distribution.getTotalCount() == 1) {\n                    assertBetween(10, 50, (int) distribution.getMean());\n                } else if (distribution.getTotalCount() == 2) {\n                    assertBetween(300, 400, (int) distribution.getMean());\n                }\n            }\n        });\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.TIMEOUT); //latency = 600\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        assertBetween(150, 400, stream.getLatestMean());\n        assertBetween(10, 50, stream.getLatestPercentile(0.0));\n        assertBetween(300, 800, stream.getLatestPercentile(100.0));\n    }\n\n    /*\n     * The following event types should not have their latency measured:\n     * THREAD_POOL_REJECTED\n     * SEMAPHORE_REJECTED\n     * SHORT_CIRCUITED\n     * RESPONSE_FROM_CACHE\n     *\n     * Newly measured (as of 1.5)\n     * BAD_REQUEST\n     * FAILURE\n     * TIMEOUT\n     */\n    @Test\n    public void testSingleBucketWithMultipleEventTypes() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-C\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                    if (distribution.getTotalCount() < 4 && distribution.getTotalCount() > 0) { //buckets before timeout latency registers\n                        assertBetween(10, 50, (int) distribution.getMean());\n                    } else if (distribution.getTotalCount() == 4){\n                        assertBetween(150, 250, (int) distribution.getMean()); //now timeout latency of 600ms is there\n                    }\n            }\n        });\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.TIMEOUT); //latency = 600\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.FAILURE, 30);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.BAD_REQUEST, 40);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n        cmd4.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertBetween(150, 350, stream.getLatestMean()); //now timeout latency of 600ms is there\n        assertBetween(10, 40, stream.getLatestPercentile(0.0));\n        assertBetween(600, 800, stream.getLatestPercentile(100.0));\n    }\n\n    @Test\n    public void testShortCircuitedCommandDoesNotGetLatencyTracked() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-D\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //3 failures is enough to trigger short-circuit.  execute those, then wait for bucket to roll\n        //next command should be a short-circuit\n        List<Command> commands = new ArrayList<Command>();\n        for (int i = 0; i < 3; i++) {\n            commands.add(Command.from(groupKey, key, HystrixEventType.FAILURE, 0));\n        }\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                assertBetween(0, 30, (int) distribution.getMean());\n            }\n        });\n\n        for (Command cmd: commands) {\n            cmd.observe();\n        }\n\n        Command shortCircuit = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        try {\n            Thread.sleep(200);\n            shortCircuit.observe();\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(3, stream.getLatest().getTotalCount());\n        assertBetween(0, 30, stream.getLatestMean());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(shortCircuit.isResponseShortCircuited());\n    }\n\n    @Test\n    public void testThreadPoolRejectedCommandDoesNotGetLatencyTracked() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-E\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //10 commands with latency should occupy the entire threadpool.  execute those, then wait for bucket to roll\n        //next command should be a thread-pool rejection\n        List<Command> commands = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            commands.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 200));\n        }\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n//                if (distribution.getTotalCount() > 0) {\n//                    assertBetween(200, 250, (int) distribution.getMean());\n//                }\n            }\n        });\n\n        for (Command cmd: commands) {\n            cmd.observe();\n        }\n\n        Command threadPoolRejected = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        try {\n            Thread.sleep(40);\n            threadPoolRejected.observe();\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(10, stream.getLatest().getTotalCount());\n        assertBetween(200, 250, stream.getLatestMean());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(threadPoolRejected.isResponseThreadPoolRejected());\n    }\n\n    @Test\n    public void testSemaphoreRejectedCommandDoesNotGetLatencyTracked() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-F\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //10 commands with latency should occupy all semaphores.  execute those, then wait for bucket to roll\n        //next command should be a semaphore rejection\n        List<Command> commands = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            commands.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 200, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                if (distribution.getTotalCount() > 0) {\n                    assertBetween(200, 250, (int) distribution.getMean());\n                }\n            }\n        });\n\n        for (final Command cmd: commands) {\n            //since these are blocking calls on the caller thread, we need a new caller thread for each command to actually get the desired concurrency\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    cmd.observe();\n                }\n            })).start();\n        }\n\n        Command semaphoreRejected = Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        try {\n            Thread.sleep(40);\n            semaphoreRejected.observe();\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(10, stream.getLatest().getTotalCount());\n        assertBetween(200, 250, stream.getLatestMean());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(semaphoreRejected.isResponseSemaphoreRejected());\n    }\n\n    @Test\n    public void testResponseFromCacheDoesNotGetLatencyTracked() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-G\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //should get 1 SUCCESS and 1 RESPONSE_FROM_CACHE\n        List<Command> commands = Command.getCommandsWithResponseFromCache(groupKey, key);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                assertTrue(distribution.getTotalCount() <= 1);\n            }\n        });\n\n        for (Command cmd: commands) {\n            cmd.observe();\n        }\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(1, stream.getLatest().getTotalCount());\n        assertBetween(0, 30, stream.getLatestMean());\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n    }\n\n    @Test\n    public void testMultipleBucketsBothGetStored() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-H\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                if (distribution.getTotalCount() == 2) {\n                    assertBetween(55, 90, (int) distribution.getMean());\n                }\n                if (distribution.getTotalCount() == 5) {\n                    assertEquals(60, 90, (long) distribution.getMean());\n                }\n            }\n        });\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.FAILURE, 100);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException ie) {\n            fail(\"Interrupted ex\");\n        }\n\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 60);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 60);\n        Command cmd5 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 70);\n\n        cmd3.observe();\n        cmd4.observe();\n        cmd5.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        assertBetween(55, 90, stream.getLatestMean());\n        assertBetween(10, 50, stream.getLatestPercentile(0.0));\n        assertBetween(100, 150, stream.getLatestPercentile(100.0));\n    }\n\n    /**\n     * The extra takes on the stream should give enough time for all of the measured latencies to age out\n     */\n    @Test\n    public void testMultipleBucketsBothGetStoredAndThenAgeOut() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Latency-I\");\n        stream = RollingCommandLatencyDistributionStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(new Subscriber<CachedValuesHistogram>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(CachedValuesHistogram distribution) {\n                System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" Received distribution with count : \" + distribution.getTotalCount() + \" and mean : \" + distribution.getMean());\n                if (distribution.getTotalCount() == 2) {\n                    assertBetween(55, 90, (int) distribution.getMean());\n                }\n                if (distribution.getTotalCount() == 5) {\n                    assertEquals(60, 90, (long) distribution.getMean());\n                }\n            }\n        });\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.FAILURE, 100);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException ie) {\n            fail(\"Interrupted ex\");\n        }\n\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 60);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 60);\n        Command cmd5 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 70);\n\n        cmd3.observe();\n        cmd4.observe();\n        cmd5.observe();\n\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        assertEquals(0, stream.getLatest().getTotalCount());\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingCommandMaxConcurrencyStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingCommandMaxConcurrencyStreamTest extends CommandStreamTest {\n    RollingCommandMaxConcurrencyStream stream;\n    HystrixRequestContext context;\n    ExecutorService threadPool;\n\n    static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Command-Concurrency\");\n\n    private static Subscriber<Integer> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(Integer maxConcurrency) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : Max of \" + maxConcurrency);\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n        threadPool = Executors.newFixedThreadPool(20);\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandMaxConcurrencyStream.reset();\n        threadPool.shutdown();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-A\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testStartsAndEndsInSameBucketProduceValue() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-B\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 100);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 100);\n\n        cmd1.observe();\n        Thread.sleep(1);\n        cmd2.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(2, stream.getLatestRollingMax());\n    }\n\n    /***\n     * 3 Commands,\n     * Command 1 gets started in Bucket A and not completed until Bucket B\n     * Commands 2 and 3 both start and end in Bucket B, and there should be a max-concurrency of 3\n     */\n    @Test\n    public void testOneCommandCarriesOverToNextBucket() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-C\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 160);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 15);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(1);\n        cmd3.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(3, stream.getLatestRollingMax());\n    }\n\n    /**\n     * BUCKETS\n     *     A    |    B    |    C    |    D    |    E    |\n     * 1:  [-------------------------------]\n     * 2:          [-------------------------------]\n     * 3:                      [--]\n     * 4:                              [--]\n     *\n     * Max concurrency should be 3\n     */\n    @Test\n    public void testMultipleCommandsCarryOverMultipleBuckets() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-D\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(100);\n        cmd3.observe();\n        Thread.sleep(100);\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(3, stream.getLatestRollingMax());\n    }\n\n    /**\n     * BUCKETS\n     *     A    |    B    |    C    |    D    |    E    |\n     * 1:  [-------------------------------]\n     * 2:          [-------------------------------]\n     * 3:                      [--]\n     * 4:                              [--]\n     *\n     * Max concurrency should be 3, but by waiting for 30 bucket rolls, final max concurrency should be 0\n     */\n    @Test\n    public void testMultipleCommandsCarryOverMultipleBucketsAndThenAgeOut() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-E\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(100);\n        cmd3.observe();\n        Thread.sleep(100);\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutResponseFromCache() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-F\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 40);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        Thread.sleep(5);\n        cmd2.observe();\n        cmd3.observe();\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutShortCircuits() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-G\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //after 3 failures, next command should short-circuit.\n        //to prove short-circuited commands don't contribute to concurrency, execute 3 FAILURES in the first bucket sequentially\n        //then when circuit is open, execute 20 concurrent commands.  they should all get short-circuited, and max concurrency should be 1\n        Command failure1 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n        Command failure2 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n        Command failure3 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n\n        List<Command> shortCircuited = new ArrayList<Command>();\n\n        for (int i = 0; i < 20; i++) {\n            shortCircuited.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100));\n        }\n\n        failure1.execute();\n        failure2.execute();\n        failure3.execute();\n\n        Thread.sleep(150);\n\n        for (Command cmd: shortCircuited) {\n            cmd.observe();\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(1, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutSemaphoreRejections() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-H\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands executed concurrently on different caller threads should saturate semaphore\n        //once these are in-flight, execute 10 more concurrently on new caller threads.\n        //since these are semaphore-rejected, the max concurrency should be 10\n\n        List<Command> saturators = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 400, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        final List<Command> rejected = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            rejected.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        for (final Command saturatingCmd: saturators) {\n            threadPool.submit(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturatingCmd.observe();\n                }\n            }));\n        }\n\n        Thread.sleep(30);\n\n        for (final Command rejectedCmd: rejected) {\n            threadPool.submit(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    rejectedCmd.observe();\n                }\n            }));\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(10, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutThreadPoolRejections() throws InterruptedException {\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"CMD-Concurrency-I\");\n        stream = RollingCommandMaxConcurrencyStream.getInstance(key, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands executed concurrently should saturate the Hystrix threadpool\n        //once these are in-flight, execute 10 more concurrently\n        //since these are threadpool-rejected, the max concurrency should be 10\n\n        List<Command> saturators = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 400));\n        }\n\n        final List<Command> rejected = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            rejected.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100));\n        }\n\n        for (final Command saturatingCmd: saturators) {\n            saturatingCmd.observe();\n        }\n\n        Thread.sleep(30);\n\n        for (final Command rejectedCmd: rejected) {\n            rejectedCmd.observe();\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertEquals(10, stream.getLatestRollingMax());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingThreadPoolEventCounterStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingThreadPoolEventCounterStreamTest extends CommandStreamTest {\n    HystrixRequestContext context;\n    RollingThreadPoolEventCounterStream stream;\n\n    private static Subscriber<long[]> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<long[]>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(long[] eventCounts) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : \" + eventCounts[0] + \" : \" + eventCounts[1]);\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandEventCounterStream.reset();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-A\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-A\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-A\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED) + stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleSuccess() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-B\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-B\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-B\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleFailure() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-C\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-C\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-C\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleTimeout() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-D\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-D\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-D\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.TIMEOUT);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSingleBadRequest() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-E\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-E\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-E\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.BAD_REQUEST);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testRequestFromCache() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-F\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-F\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-F\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        CommandStreamTest.Command cmd3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        cmd2.observe();\n        cmd3.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n        //RESPONSE_FROM_CACHE should not show up at all in thread pool counters - just the success\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testShortCircuited() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-G\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-G\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-G\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //3 failures in a row will trip circuit.  let bucket roll once then submit 2 requests.\n        //should see 3 FAILUREs and 2 SHORT_CIRCUITs and each should see a FALLBACK_SUCCESS\n\n        CommandStreamTest.Command failure1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n        CommandStreamTest.Command failure3 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20);\n\n        CommandStreamTest.Command shortCircuit1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n        CommandStreamTest.Command shortCircuit2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS);\n\n        failure1.observe();\n        failure2.observe();\n        failure3.observe();\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        shortCircuit1.observe();\n        shortCircuit2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(shortCircuit1.isResponseShortCircuited());\n        assertTrue(shortCircuit2.isResponseShortCircuited());\n\n        //only the FAILUREs should show up in thread pool counters\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(3, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testSemaphoreRejected() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-H\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-H\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-H\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate semaphore when called from different threads.\n        //submit 2 more requests and they should be SEMAPHORE_REJECTED\n        //should see 10 SUCCESSes, 2 SEMAPHORE_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<Command> saturators = new ArrayList<Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 500, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            new Thread(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturator.observe();\n                }\n            })).start();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseSemaphoreRejected());\n        assertTrue(rejected2.isResponseSemaphoreRejected());\n\n        //none of these got executed on a thread-pool, so thread pool metrics should be 0\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testThreadPoolRejected() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-I\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-I\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-I\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //10 commands will saturate threadpools when called concurrently.\n        //submit 2 more requests and they should be THREADPOOL_REJECTED\n        //should see 10 SUCCESSes, 2 THREADPOOL_REJECTED and 2 FALLBACK_SUCCESSes\n\n        List<CommandStreamTest.Command> saturators = new ArrayList<CommandStreamTest.Command>();\n\n        for (int i = 0; i < 10; i++) {\n            saturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 200));\n        }\n\n        CommandStreamTest.Command rejected1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n        CommandStreamTest.Command rejected2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 0);\n\n        for (final CommandStreamTest.Command saturator : saturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(100);\n        } catch (InterruptedException ie) {\n            fail(ie.getMessage());\n        }\n\n        rejected1.observe();\n        rejected2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(rejected1.isResponseThreadPoolRejected());\n        assertTrue(rejected2.isResponseThreadPoolRejected());\n\n        //all 12 commands got submitted to thread pool, 10 accepted, 2 rejected is expected\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(10, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(2, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-J\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-J\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-J\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_FAILURE);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackMissing() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-K\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-K\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-K\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_MISSING);\n\n        cmd.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(1, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testFallbackRejection() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-L\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-L\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-L\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 500);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(5).subscribe(getSubscriber(latch));\n\n        //fallback semaphore size is 5.  So let 5 commands saturate that semaphore, then\n        //let 2 more commands go to fallback.  they should get rejected by the fallback-semaphore\n\n        List<CommandStreamTest.Command> fallbackSaturators = new ArrayList<CommandStreamTest.Command>();\n        for (int i = 0; i < 5; i++) {\n            fallbackSaturators.add(CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 400));\n        }\n\n        CommandStreamTest.Command rejection1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n        CommandStreamTest.Command rejection2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 20, HystrixEventType.FALLBACK_SUCCESS, 0);\n\n        for (CommandStreamTest.Command saturator: fallbackSaturators) {\n            saturator.observe();\n        }\n\n        try {\n            Thread.sleep(70);\n        } catch (InterruptedException ex) {\n            fail(ex.getMessage());\n        }\n\n        rejection1.observe();\n        rejection2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        //all 7 commands executed on-thread, so should be executed according to thread-pool metrics\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(7, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n\n    @Test\n    public void testMultipleEventsOverTimeGetStoredAndAgeOut() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-M\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-M\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingCounter-M\");\n        stream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, 10, 250);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        //by doing a take(20), we ensure that all rolling counts go back to 0\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(20).subscribe(getSubscriber(latch));\n\n        CommandStreamTest.Command cmd1 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.SUCCESS, 20);\n        CommandStreamTest.Command cmd2 = CommandStreamTest.Command.from(groupKey, key, HystrixEventType.FAILURE, 10);\n\n        cmd1.observe();\n        cmd2.observe();\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n\n        //all commands should have aged out\n        assertEquals(2, stream.getLatest().length);\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED));\n        assertEquals(0, stream.getLatestCount(HystrixEventType.ThreadPool.REJECTED));\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/consumer/RollingThreadPoolMaxConcurrencyStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.consumer;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport rx.Subscriber;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.*;\n\npublic class RollingThreadPoolMaxConcurrencyStreamTest extends CommandStreamTest {\n    RollingThreadPoolMaxConcurrencyStream stream;\n    HystrixRequestContext context;\n    ExecutorService threadPool;\n\n    private static Subscriber<Integer> getSubscriber(final CountDownLatch latch) {\n        return new Subscriber<Integer>() {\n            @Override\n            public void onCompleted() {\n                latch.countDown();\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                fail(e.getMessage());\n            }\n\n            @Override\n            public void onNext(Integer maxConcurrency) {\n                System.out.println(\"OnNext @ \" + System.currentTimeMillis() + \" : Max of \" + maxConcurrency);\n            }\n        };\n    }\n\n    @Before\n    public void setUp() {\n        context = HystrixRequestContext.initializeContext();\n        threadPool = Executors.newFixedThreadPool(20);\n    }\n\n    @After\n    public void tearDown() {\n        context.shutdown();\n        stream.unsubscribe();\n        RollingCommandMaxConcurrencyStream.reset();\n        threadPool.shutdown();\n    }\n\n    @Test\n    public void testEmptyStreamProducesZeros() {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-A\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-A\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-A\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //no writes\n\n        try {\n            assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        } catch (InterruptedException ex) {\n            fail(\"Interrupted ex\");\n        }\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testStartsAndEndsInSameBucketProduceValue() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-B\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-B\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-B\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 50);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 40);\n\n        cmd1.observe();\n        Thread.sleep(1);\n        cmd2.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(2, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testStartsAndEndsInSameBucketSemaphoreIsolated() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-C\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-C\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-C\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 14, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE);\n\n        cmd1.observe();\n        Thread.sleep(1);\n        cmd2.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        //since commands run in semaphore isolation, they are not tracked by threadpool metrics\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n\n    /***\n     * 3 Commands,\n     * Command 1 gets started in Bucket A and not completed until Bucket B\n     * Commands 2 and 3 both start and end in Bucket B, and there should be a max-concurrency of 3\n     */\n    @Test\n    public void testOneCommandCarriesOverToNextBucket() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-D\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-D\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-D\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 560);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 50);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 75);\n\n        cmd1.observe();\n        Thread.sleep(150); //bucket roll\n        cmd2.observe();\n        Thread.sleep(1);\n        cmd3.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(3, stream.getLatestRollingMax());\n    }\n\n    /**\n     * BUCKETS\n     *     A    |    B    |    C    |    D    |    E    |\n     * 1:  [-------------------------------]\n     * 2:          [-------------------------------]\n     * 3:                      [--]\n     * 4:                              [--]\n     *\n     * Max concurrency should be 3\n     */\n    @Test\n    public void testMultipleCommandsCarryOverMultipleBuckets() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-E\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-E\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-E\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(100);\n        cmd3.observe();\n        Thread.sleep(100);\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(3, stream.getLatestRollingMax());\n    }\n\n    /**\n     * BUCKETS\n     *     A    |    B    |    C    |    D    |    E    |\n     * 1:  [-------------------------------]              ThreadPool x\n     * 2:          [-------------------------------]                 y\n     * 3:                      [--]                                  x\n     * 4:                              [--]                          x\n     *\n     * Same input data as above test, just that command 2 runs in a separate threadpool, so concurrency should not get tracked\n     * Max concurrency should be 2 for x\n     */\n    @Test\n    public void testMultipleCommandsCarryOverMultipleBucketsForMultipleThreadPools() throws InterruptedException {\n        HystrixCommandGroupKey groupKeyX = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-X\");\n        HystrixCommandGroupKey groupKeyY = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-Y\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-X\");\n        HystrixCommandKey keyX = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-X\");\n        HystrixCommandKey keyY = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-Y\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKeyX, keyX, HystrixEventType.SUCCESS, 300);\n        Command cmd2 = Command.from(groupKeyY, keyY, HystrixEventType.SUCCESS, 300);\n        Command cmd3 = Command.from(groupKeyX, keyY, HystrixEventType.SUCCESS, 10);\n        Command cmd4 = Command.from(groupKeyX, keyY, HystrixEventType.SUCCESS, 10);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(100);\n        cmd3.observe();\n        Thread.sleep(100);\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(2, stream.getLatestRollingMax());\n    }\n\n    /**\n     * BUCKETS\n     *     A    |    B    |    C    |    D    |    E    |\n     * 1:  [-------------------------------]\n     * 2:          [-------------------------------]\n     * 3:                      [--]\n     * 4:                              [--]\n     *\n     * Max concurrency should be 3, but by waiting for 30 bucket rolls, final max concurrency should be 0\n     */\n    @Test\n    public void testMultipleCommandsCarryOverMultipleBucketsAndThenAgeOut() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-F\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-F\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-F\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(30).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 300);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 10);\n\n        cmd1.observe();\n        Thread.sleep(100); //bucket roll\n        cmd2.observe();\n        Thread.sleep(100);\n        cmd3.observe();\n        Thread.sleep(100);\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutResponseFromCache() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-G\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-G\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-G\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        Command cmd1 = Command.from(groupKey, key, HystrixEventType.SUCCESS, 40);\n        Command cmd2 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        Command cmd3 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n        Command cmd4 = Command.from(groupKey, key, HystrixEventType.RESPONSE_FROM_CACHE);\n\n        cmd1.observe();\n        Thread.sleep(5);\n        cmd2.observe();\n        cmd3.observe();\n        cmd4.observe();\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        assertTrue(cmd2.isResponseFromCache());\n        assertTrue(cmd3.isResponseFromCache());\n        assertTrue(cmd4.isResponseFromCache());\n        assertEquals(1, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutShortCircuits() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-H\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-H\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-H\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //after 3 failures, next command should short-circuit.\n        //to prove short-circuited commands don't contribute to concurrency, execute 3 FAILURES in the first bucket sequentially\n        //then when circuit is open, execute 20 concurrent commands.  they should all get short-circuited, and max concurrency should be 1\n        Command failure1 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n        Command failure2 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n        Command failure3 = Command.from(groupKey, key, HystrixEventType.FAILURE);\n\n        List<Command> shortCircuited = new ArrayList<Command>();\n\n        for (int i = 0; i < 20; i++) {\n            shortCircuited.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100));\n        }\n\n        failure1.execute();\n        failure2.execute();\n        failure3.execute();\n\n        Thread.sleep(150);\n\n        for (Command cmd: shortCircuited) {\n            cmd.observe();\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        for (Command cmd: shortCircuited) {\n            assertTrue(cmd.isResponseShortCircuited());\n        }\n        assertEquals(1, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutSemaphoreRejections() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-I\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-I\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-I\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands executed concurrently on different caller threads should saturate semaphore\n        //once these are in-flight, execute 10 more concurrently on new caller threads.\n        //since these are semaphore-rejected, the max concurrency should be 10\n\n        List<Command> saturators = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 400, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        final List<Command> rejected = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            rejected.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100, HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE));\n        }\n\n        for (final Command saturatingCmd: saturators) {\n            threadPool.submit(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    saturatingCmd.observe();\n                }\n            }));\n        }\n\n        Thread.sleep(30);\n\n        for (final Command rejectedCmd: rejected) {\n            threadPool.submit(new HystrixContextRunnable(new Runnable() {\n                @Override\n                public void run() {\n                    rejectedCmd.observe();\n                }\n            }));\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\n        for (Command rejectedCmd: rejected) {\n            assertTrue(rejectedCmd.isResponseSemaphoreRejected() || rejectedCmd.isResponseShortCircuited());\n        }\n        //should be 0 since all are executed in a semaphore\n        assertEquals(0, stream.getLatestRollingMax());\n    }\n\n    @Test\n    public void testConcurrencyStreamProperlyFiltersOutThreadPoolRejections() throws InterruptedException {\n        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"ThreadPool-Concurrency-J\");\n        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool-Concurrency-J\");\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"RollingConcurrency-J\");\n        stream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, 10, 100);\n        stream.startCachingStreamValuesIfUnstarted();\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        stream.observe().take(10).subscribe(getSubscriber(latch));\n\n        //10 commands executed concurrently should saturate the Hystrix threadpool\n        //once these are in-flight, execute 10 more concurrently\n        //since these are threadpool-rejected, the max concurrency should be 10\n\n        List<Command> saturators = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            saturators.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 400));\n        }\n\n        final List<Command> rejected = new ArrayList<Command>();\n        for (int i = 0; i < 10; i++) {\n            rejected.add(Command.from(groupKey, key, HystrixEventType.SUCCESS, 100));\n        }\n\n        for (final Command saturatingCmd: saturators) {\n            saturatingCmd.observe();\n        }\n\n        Thread.sleep(30);\n\n        for (final Command rejectedCmd: rejected) {\n            rejectedCmd.observe();\n        }\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"ReqLog : \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n        for (Command rejectedCmd: rejected) {\n            assertTrue(rejectedCmd.isResponseThreadPoolRejected());\n        }\n\n        //this should not count rejected commands\n        assertEquals(10, stream.getLatestRollingMax());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/metric/sample/HystrixUtilizationStreamTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.metric.sample;\n\nimport com.hystrix.junit.HystrixRequestContextRule;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.CommandStreamTest;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\nimport rx.functions.Action0;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.schedulers.Schedulers;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\npublic class HystrixUtilizationStreamTest extends CommandStreamTest {\n\n    @Rule\n    public HystrixRequestContextRule ctx = new HystrixRequestContextRule();\n\n    HystrixUtilizationStream stream;\n    private final static HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"Util\");\n    private final static HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(\"Command\");\n\n    @Before\n    public void init() {\n        stream = HystrixUtilizationStream.getNonSingletonInstanceOnlyUsedInUnitTests(10);\n    }\n\n    @Test\n    public void testStreamHasData() throws Exception {\n        final AtomicBoolean commandShowsUp = new AtomicBoolean(false);\n        final AtomicBoolean threadPoolShowsUp = new AtomicBoolean(false);\n        final CountDownLatch latch = new CountDownLatch(1);\n        final int NUM = 10;\n\n        for (int i = 0; i < 2; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.observe();\n        }\n\n        stream.observe().take(NUM).subscribe(\n                new Subscriber<HystrixUtilization>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" OnError : \" + e);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixUtilization utilization) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Received data with : \" + utilization.getCommandUtilizationMap().size() + \" commands\");\n                        if (utilization.getCommandUtilizationMap().containsKey(commandKey)) {\n                            commandShowsUp.set(true);\n                        }\n                        if (!utilization.getThreadPoolUtilizationMap().isEmpty()) {\n                            threadPoolShowsUp.set(true);\n                        }\n                    }\n                });\n\n        assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(commandShowsUp.get());\n        assertTrue(threadPoolShowsUp.get());\n    }\n\n    @Test\n    public void testTwoSubscribersOneUnsubscribes() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixUtilization>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixUtilization utilization) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + utilization);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixUtilization>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixUtilization utilization) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + utilization);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute 1 command, then unsubscribe from first stream. then execute the rest\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 1) {\n                s1.unsubscribe();\n            }\n        }\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n        assertTrue(\"s1 got less data than s2\", payloads2.get() > payloads1.get());\n    }\n\n    @Test\n    public void testTwoSubscribersBothUnsubscribe() throws Exception {\n        final CountDownLatch latch1 = new CountDownLatch(1);\n        final CountDownLatch latch2 = new CountDownLatch(1);\n        final AtomicInteger payloads1 = new AtomicInteger(0);\n        final AtomicInteger payloads2 = new AtomicInteger(0);\n\n        Subscription s1 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch1.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixUtilization>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnCompleted\");\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnError : \" + e);\n                        latch1.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixUtilization utilization) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 1 OnNext : \" + utilization);\n                        payloads1.incrementAndGet();\n                    }\n                });\n\n        Subscription s2 = stream\n                .observe()\n                .take(100)\n                .doOnUnsubscribe(new Action0() {\n                    @Override\n                    public void call() {\n                        latch2.countDown();\n                    }\n                })\n                .subscribe(new Subscriber<HystrixUtilization>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnCompleted\");\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnError : \" + e);\n                        latch2.countDown();\n                    }\n\n                    @Override\n                    public void onNext(HystrixUtilization utilization) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : Dashboard 2 OnNext : \" + utilization);\n                        payloads2.incrementAndGet();\n                    }\n                });\n        //execute 2 commands, then unsubscribe from both streams, then execute the rest\n        for (int i = 0; i < 10; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n            if (i == 2) {\n                s1.unsubscribe();\n                s2.unsubscribe();\n            }\n        }\n        assertFalse(stream.isSourceCurrentlySubscribed());  //both subscriptions have been cancelled - source should be too\n\n        assertTrue(latch1.await(10000, TimeUnit.MILLISECONDS));\n        assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS));\n        System.out.println(\"s1 got : \" + payloads1.get() + \", s2 got : \" + payloads2.get());\n        assertTrue(\"s1 got data\", payloads1.get() > 0);\n        assertTrue(\"s2 got data\", payloads2.get() > 0);\n    }\n\n    @Test\n    public void testTwoSubscribersOneSlowOneFast() throws Exception {\n        final CountDownLatch latch = new CountDownLatch(1);\n        final AtomicBoolean foundError = new AtomicBoolean(false);\n\n        Observable<HystrixUtilization> fast = stream\n                .observe()\n                .observeOn(Schedulers.newThread());\n        Observable<HystrixUtilization> slow = stream\n                .observe()\n                .observeOn(Schedulers.newThread())\n                .map(new Func1<HystrixUtilization, HystrixUtilization>() {\n                    @Override\n                    public HystrixUtilization call(HystrixUtilization util) {\n                        try {\n                            Thread.sleep(100);\n                            return util;\n                        } catch (InterruptedException ex) {\n                            return util;\n                        }\n                    }\n                });\n\n        Observable<Boolean> checkZippedEqual = Observable.zip(fast, slow, new Func2<HystrixUtilization, HystrixUtilization, Boolean>() {\n            @Override\n            public Boolean call(HystrixUtilization payload, HystrixUtilization payload2) {\n                return payload == payload2;\n            }\n        });\n\n        Subscription s1 = checkZippedEqual\n                .take(10000)\n                .subscribe(new Subscriber<Boolean>() {\n                    @Override\n                    public void onCompleted() {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnCompleted\");\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnError : \" + e);\n                        e.printStackTrace();\n                        foundError.set(true);\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void onNext(Boolean b) {\n                        //System.out.println(System.currentTimeMillis() + \" : \" + Thread.currentThread().getName() + \" : OnNext : \" + b);\n                    }\n                });\n\n        for (int i = 0; i < 50; i++) {\n            HystrixCommand<Integer> cmd = Command.from(groupKey, commandKey, HystrixEventType.SUCCESS, 50);\n            cmd.execute();\n        }\n\n        latch.await(10000, TimeUnit.MILLISECONDS);\n        assertFalse(foundError.get());\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/HystrixPluginsTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy;\n\nimport static java.util.Arrays.asList;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.ServiceConfigurationError;\nimport java.util.Vector;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\nimport org.junit.After;\nimport org.junit.Test;\nimport org.slf4j.Logger;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.strategy.HystrixPlugins.LoggerSupplier;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;\nimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;\nimport com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperties;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesSystemProperties;\nimport com.netflix.hystrix.strategy.properties.HystrixDynamicProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\n\npublic class HystrixPluginsTest {\n    @After\n    public void reset() {\n        //HystrixPlugins.reset();\n        dynamicPropertyEvents.clear();\n        System.clearProperty(\"hystrix.plugin.HystrixDynamicProperties.implementation\");\n    }\n    \n    private static ConcurrentLinkedQueue<String> dynamicPropertyEvents = new ConcurrentLinkedQueue<String>();\n\n    \n    @Test\n    public void testDynamicProperties() throws Exception {\n        fakeServiceLoaderResource = \n                \"FAKE_META_INF_SERVICES/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties\";\n        HystrixPlugins plugins = setupMockServiceLoader();\n        HystrixDynamicProperties properties = plugins.getDynamicProperties();\n        plugins.getCommandExecutionHook();\n        plugins.getPropertiesStrategy();\n        assertTrue(properties instanceof MockHystrixDynamicPropertiesTest);\n\n        assertEvents(\n                \"[serviceloader: META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties\"\n                        + \", debug: [Created HystrixDynamicProperties instance by loading from ServiceLoader. Using class: {}, com.netflix.hystrix.strategy.HystrixPluginsTest.MockHystrixDynamicPropertiesTest]\"\n                        + \", property: hystrix.plugin.HystrixCommandExecutionHook.implementation\"\n                        + \", serviceloader: META-INF/services/com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook\"\n                        + \", property: hystrix.plugin.HystrixPropertiesStrategy.implementation\"\n                        + \", serviceloader: META-INF/services/com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy]\");\n    }\n    \n    void assertEvents(String expect) throws Exception {\n        List<String> keys = getEvents();\n        String actual = keys.toString();\n        if (! actual.equals(expect)) {\n            javaPrintList(System.out, keys);\n        }\n        assertEquals(expect, actual);\n    }\n    \n    static List<String> getEvents() {\n        return new ArrayList<String>(dynamicPropertyEvents);\n    }\n    \n    static void javaPrintList(Appendable a, Iterable<String> list) throws IOException {\n        boolean first = true;\n        \n        for (String o : list) {\n            if (first) {\n                a.append(\"\\\"[\");\n                first = false;\n            }\n            else {\n                a.append(\"\\\"\");\n                a.append(\"\\n+ \\\", \");\n            }\n            a.append(o);\n        }\n        a.append(\"]\\\"\");\n    }\n    \n    @Test(expected=ServiceConfigurationError.class)\n    public void testDynamicPropertiesFailure() throws Exception {\n        /*\n         * James Bond: Do you expect me to talk?\n         * Auric Goldfinger: No, Mr. Bond, I expect you to die!\n         */\n        fakeServiceLoaderResource = \n                \"FAKE_META_INF_SERVICES/com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesFail\";\n        HystrixPlugins plugins = setupMockServiceLoader();\n        plugins.getDynamicProperties();\n\n    }\n    \n    @Test\n    public void testDynamicSystemProperties() throws Exception {\n        //On the off chance this is the first test lets not screw up all the other tests\n        HystrixPlugins.getInstance();\n        \n        System.setProperty(\"hystrix.plugin.HystrixDynamicProperties.implementation\", \n                \"com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesSystemProperties\");\n        \n        HystrixPlugins plugins = setupMockServiceLoader();\n        assertTrue(plugins.getDynamicProperties() instanceof HystrixDynamicPropertiesSystemProperties);\n        \n        HystrixDynamicProperties p = plugins.getDynamicProperties();\n        //Some minimum testing of system properties wrapper\n        //this probably should be in its own test class.\n        assertTrue(p.getBoolean(\"USE_DEFAULT\", true).get());\n        assertEquals(\"string\", p.getString(\"USE_DEFAULT\", \"string\").get());\n        assertEquals(1L, p.getLong(\"USE_DEFAULT\", 1L).get().longValue());\n        assertEquals(1, p.getInteger(\"USE_DEFAULT\", 1).get().intValue());\n        assertNotNull(p.getString(\"path.separator\", null).get());\n        \n        assertEvents(\"[debug: [Created HystrixDynamicProperties instance from System property named \\\"hystrix.plugin.HystrixDynamicProperties.implementation\\\". Using class: {}, com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesSystemProperties]]\");\n\n        System.clearProperty(\"hystrix.plugin.HystrixDynamicProperties.implementation\");\n\n    }\n        \n    static String fakeServiceLoaderResource = \n            \"FAKE_META_INF_SERVICES/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties\";\n    \n    private HystrixPlugins setupMockServiceLoader() throws Exception {\n        final ClassLoader realLoader = HystrixPlugins.class.getClassLoader();\n        ClassLoader loader = new WrappedClassLoader(realLoader) {\n\n            @Override\n            public Enumeration<URL> getResources(String name) throws IOException {\n                dynamicPropertyEvents.add(\"serviceloader: \" + name);\n                final Enumeration<URL> r;\n                if (name.endsWith(\"META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties\")) {\n                    Vector<URL> vs = new Vector<URL>();\n                    URL u = super.getResource(fakeServiceLoaderResource);\n                    vs.add(u);\n                    return vs.elements();\n                } else {\n                    r = super.getResources(name);\n                }\n                return r;\n            }\n        };\n        final Logger mockLogger = (Logger) \n                Proxy.newProxyInstance(realLoader, new Class<?>[] {Logger.class}, new MockLoggerInvocationHandler());\n        return HystrixPlugins.create(loader, new LoggerSupplier() {\n            @Override\n            public Logger getLogger() {\n                return mockLogger;\n            }\n        });\n    }\n    \n    static class MockLoggerInvocationHandler implements InvocationHandler {\n\n        @Override\n        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n            dynamicPropertyEvents.offer(method.getName() + \": \" + asList(args));\n            return null;\n        }\n        \n    }\n\n    static class WrappedClassLoader extends ClassLoader {\n\n        final ClassLoader delegate;\n\n        public WrappedClassLoader(ClassLoader delegate) {\n            super();\n            this.delegate = delegate;\n        }\n\n        public Class<?> loadClass(String name) throws ClassNotFoundException {\n            return delegate.loadClass(name);\n        }\n\n        public URL getResource(String name) {\n            return delegate.getResource(name);\n        }\n\n        public Enumeration<URL> getResources(String name) throws IOException {\n            return delegate.getResources(name);\n        }\n\n        public InputStream getResourceAsStream(String name) {\n            return delegate.getResourceAsStream(name);\n        }\n\n        public void setDefaultAssertionStatus(boolean enabled) {\n            delegate.setDefaultAssertionStatus(enabled);\n        }\n\n        public void setPackageAssertionStatus(String packageName, boolean enabled) {\n            delegate.setPackageAssertionStatus(packageName, enabled);\n        }\n\n        public void setClassAssertionStatus(String className, boolean enabled) {\n            delegate.setClassAssertionStatus(className, enabled);\n        }\n\n        public void clearAssertionStatus() {\n            delegate.clearAssertionStatus();\n        }\n    }\n\n    private static class NoOpProperty<T> implements HystrixDynamicProperty<T> {\n\n        @Override\n        public T get() {\n            return null;\n        }\n\n        @Override\n        public void addCallback(Runnable callback) {\n        }\n\n        @Override\n        public String getName() {\n            return \"NOP\";\n        }\n        \n    }\n    \n    public static class MockHystrixDynamicPropertiesTest implements HystrixDynamicProperties {\n\n        @Override\n        public HystrixDynamicProperty<String> getString(String name, String fallback) {\n            dynamicPropertyEvents.offer(\"property: \" + name);\n            return new NoOpProperty<String>();\n        }\n\n        @Override\n        public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback) {\n            dynamicPropertyEvents.offer(\"property: \" + name);\n            return new NoOpProperty<Integer>();\n        }\n\n        @Override\n        public HystrixDynamicProperty<Long> getLong(String name, Long fallback) {\n            dynamicPropertyEvents.offer(\"property: \" + name);\n            return new NoOpProperty<Long>();\n\n        }\n\n        @Override\n        public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback) {\n            dynamicPropertyEvents.offer(\"property: \" + name);\n            return new NoOpProperty<Boolean>();\n\n        }\n        \n    }\n\n    /*    @Test\n    public void testCommandExecutionHookDefaultImpl() {\n        HystrixCommandExecutionHook impl = HystrixPlugins.getInstance().getCommandExecutionHook();\n        assertTrue(impl instanceof HystrixCommandExecutionHookDefault);\n    }\n\n    @Test\n    public void testCommandExecutionHookViaRegisterMethod() {\n        HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixCommandExecutionHookTestImpl());\n        HystrixCommandExecutionHook impl = HystrixPlugins.getInstance().getCommandExecutionHook();\n        assertTrue(impl instanceof HystrixCommandExecutionHookTestImpl);\n\t}*/\n\n    public static class HystrixCommandExecutionHookTestImpl extends HystrixCommandExecutionHook {\n    }\n\n    /*@Test\n    public void testEventNotifierDefaultImpl() {\n        HystrixEventNotifier impl = HystrixPlugins.getInstance().getEventNotifier();\n        assertTrue(impl instanceof HystrixEventNotifierDefault);\n    }\n\n    @Test\n    public void testEventNotifierViaRegisterMethod() {\n        HystrixPlugins.getInstance().registerEventNotifier(new HystrixEventNotifierTestImpl());\n        HystrixEventNotifier impl = HystrixPlugins.getInstance().getEventNotifier();\n        assertTrue(impl instanceof HystrixEventNotifierTestImpl);\n    }\n\n    @Test\n    public void testEventNotifierViaProperty() {\n        try {\n            String fullClass = HystrixEventNotifierTestImpl.class.getName();\n            System.setProperty(\"hystrix.plugin.HystrixEventNotifier.implementation\", fullClass);\n            HystrixEventNotifier impl = HystrixPlugins.getInstance().getEventNotifier();\n            assertTrue(impl instanceof HystrixEventNotifierTestImpl);\n        } finally {\n            System.clearProperty(\"hystrix.plugin.HystrixEventNotifier.implementation\");\n        }\n\t}*/\n\n    // inside UnitTest so it is stripped from Javadocs\n    public static class HystrixEventNotifierTestImpl extends HystrixEventNotifier {\n        // just use defaults\n    }\n\n    /*@Test\n    public void testConcurrencyStrategyDefaultImpl() {\n        HystrixConcurrencyStrategy impl = HystrixPlugins.getInstance().getConcurrencyStrategy();\n        assertTrue(impl instanceof HystrixConcurrencyStrategyDefault);\n    }\n\n    @Test\n    public void testConcurrencyStrategyViaRegisterMethod() {\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(new HystrixConcurrencyStrategyTestImpl());\n        HystrixConcurrencyStrategy impl = HystrixPlugins.getInstance().getConcurrencyStrategy();\n        assertTrue(impl instanceof HystrixConcurrencyStrategyTestImpl);\n    }\n\n    @Test\n    public void testConcurrencyStrategyViaProperty() {\n        try {\n            String fullClass = HystrixConcurrencyStrategyTestImpl.class.getName();\n            System.setProperty(\"hystrix.plugin.HystrixConcurrencyStrategy.implementation\", fullClass);\n            HystrixConcurrencyStrategy impl = HystrixPlugins.getInstance().getConcurrencyStrategy();\n            assertTrue(impl instanceof HystrixConcurrencyStrategyTestImpl);\n        } finally {\n            System.clearProperty(\"hystrix.plugin.HystrixConcurrencyStrategy.implementation\");\n        }\n\t}*/\n\n    // inside UnitTest so it is stripped from Javadocs\n    public static class HystrixConcurrencyStrategyTestImpl extends HystrixConcurrencyStrategy {\n        // just use defaults\n    }\n\n    /*@Test\n    public void testMetricsPublisherDefaultImpl() {\n        HystrixMetricsPublisher impl = HystrixPlugins.getInstance().getMetricsPublisher();\n        assertTrue(impl instanceof HystrixMetricsPublisherDefault);\n    }\n\n    @Test\n    public void testMetricsPublisherViaRegisterMethod() {\n        HystrixPlugins.getInstance().registerMetricsPublisher(new HystrixMetricsPublisherTestImpl());\n        HystrixMetricsPublisher impl = HystrixPlugins.getInstance().getMetricsPublisher();\n        assertTrue(impl instanceof HystrixMetricsPublisherTestImpl);\n    }\n\n    @Test\n    public void testMetricsPublisherViaProperty() {\n        try {\n            String fullClass = HystrixMetricsPublisherTestImpl.class.getName();\n            System.setProperty(\"hystrix.plugin.HystrixMetricsPublisher.implementation\", fullClass);\n            HystrixMetricsPublisher impl = HystrixPlugins.getInstance().getMetricsPublisher();\n            assertTrue(impl instanceof HystrixMetricsPublisherTestImpl);\n        } finally {\n            System.clearProperty(\"hystrix.plugin.HystrixMetricsPublisher.implementation\");\n        }\n\t}*/\n\n    // inside UnitTest so it is stripped from Javadocs\n    public static class HystrixMetricsPublisherTestImpl extends HystrixMetricsPublisher {\n        // just use defaults\n    }\n\n    /*@Test\n    public void testPropertiesStrategyDefaultImpl() {\n        HystrixPropertiesStrategy impl = HystrixPlugins.getInstance().getPropertiesStrategy();\n        assertTrue(impl instanceof HystrixPropertiesStrategyDefault);\n    }\n\n    @Test\n    public void testPropertiesStrategyViaRegisterMethod() {\n        HystrixPlugins.getInstance().registerPropertiesStrategy(new HystrixPropertiesStrategyTestImpl());\n        HystrixPropertiesStrategy impl = HystrixPlugins.getInstance().getPropertiesStrategy();\n        assertTrue(impl instanceof HystrixPropertiesStrategyTestImpl);\n    }\n\n    @Test\n    public void testPropertiesStrategyViaProperty() {\n        try {\n            String fullClass = HystrixPropertiesStrategyTestImpl.class.getName();\n            System.setProperty(\"hystrix.plugin.HystrixPropertiesStrategy.implementation\", fullClass);\n            HystrixPropertiesStrategy impl = HystrixPlugins.getInstance().getPropertiesStrategy();\n            assertTrue(impl instanceof HystrixPropertiesStrategyTestImpl);\n        } finally {\n            System.clearProperty(\"hystrix.plugin.HystrixPropertiesStrategy.implementation\");\n        }\n\t}*/\n\n    // inside UnitTest so it is stripped from Javadocs\n    public static class HystrixPropertiesStrategyTestImpl extends HystrixPropertiesStrategy {\n        // just use defaults\n    }\n    \n    /*@Test\n    public void testRequestContextViaPluginInTimeout() {\n        HystrixPlugins.getInstance().registerConcurrencyStrategy(new HystrixConcurrencyStrategy() {\n            @Override\n            public <T> Callable<T> wrapCallable(final Callable<T> callable) {\n                return new RequestIdCallable<T>(callable);\n            }\n        });\n\n        HystrixRequestContext context = HystrixRequestContext.initializeContext();\n\n        testRequestIdThreadLocal.set(\"foobar\");\n        final AtomicReference<String> valueInTimeout = new AtomicReference<String>();\n\n        new DummyCommand().toObservable()\n                .doOnError(new Action1<Throwable>() {\n                    @Override\n                    public void call(Throwable throwable) {\n                        System.out.println(\"initialized = \" + HystrixRequestContext.isCurrentThreadInitialized());\n                        System.out.println(\"requestId (timeout) = \" + testRequestIdThreadLocal.get());\n                        valueInTimeout.set(testRequestIdThreadLocal.get());\n                    }\n                })\n                .materialize()\n                .toBlocking().single();\n\n        context.shutdown();\n        Hystrix.reset();\n        \n        assertEquals(\"foobar\", valueInTimeout.get());\n\t}*/\n\n    private static class RequestIdCallable<T> implements Callable<T> {\n        private final Callable<T> callable;\n        private final String requestId;\n\n        public RequestIdCallable(Callable<T> callable) {\n            this.callable = callable;\n            this.requestId = testRequestIdThreadLocal.get();\n        }\n\n        @Override\n        public T call() throws Exception {\n            String original = testRequestIdThreadLocal.get();\n            testRequestIdThreadLocal.set(requestId);\n            try {\n                return callable.call();\n            } finally {\n                testRequestIdThreadLocal.set(original);\n            }\n        }\n    }\n    \n    private static final ThreadLocal<String> testRequestIdThreadLocal = new ThreadLocal<String>();\n\n    public static class DummyCommand extends HystrixCommand<Void> {\n\n        public DummyCommand() {\n            super(HystrixCommandGroupKey.Factory.asKey(\"Dummy\"));\n        }\n\n        @Override\n        protected Void run() throws Exception {\n            System.out.println(\"requestId (run) = \" + testRequestIdThreadLocal.get());\n            Thread.sleep(2000);\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/concurrency/HystrixConcurrencyStrategyTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.lang.IllegalStateException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport rx.functions.Action1;\nimport rx.functions.Func1;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixRequestLog;\n\npublic class HystrixConcurrencyStrategyTest {\n    @Before\n    public void prepareForTest() {\n        /* we must call this to simulate a new request lifecycle running and clearing caches */\n        HystrixRequestContext.initializeContext();\n    }\n\n    @After\n    public void cleanup() {\n        shutdownContextIfExists();\n\n        // force properties to be clean as well\n        ConfigurationManager.getConfigInstance().clear();\n    }\n\n    /**\n     * If the RequestContext does not get transferred across threads correctly this blows up.\n     * No specific assertions are necessary.\n     */\n    @Test\n    public void testRequestContextPropagatesAcrossObserveOnPool() {\n        new SimpleCommand().execute();\n        new SimpleCommand().observe().map(new Func1<String, String>() {\n\n            @Override\n            public String call(String s) {\n                System.out.println(\"Map => Commands: \" + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());\n                return s;\n            }\n        }).toBlocking().forEach(new Action1<String>() {\n\n            @Override\n            public void call(String s) {\n                System.out.println(\"Result [\" + s + \"] => Commands: \" + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());\n            }\n        });\n    }\n\n    private static class SimpleCommand extends HystrixCommand<String> {\n\n        public SimpleCommand() {\n            super(HystrixCommandGroupKey.Factory.asKey(\"SimpleCommand\"));\n        }\n\n        @Override\n        protected String run() throws Exception {\n            if (HystrixRequestContext.isCurrentThreadInitialized()) {\n                System.out.println(\"Executing => Commands: \" + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());\n            }\n            return \"Hello\";\n        }\n\n    }\n\n    @Test\n    public void testThreadContextOnTimeout() {\n        final AtomicBoolean isInitialized = new AtomicBoolean();\n        new TimeoutCommand().toObservable()\n                .doOnError(new Action1<Throwable>() {\n                    @Override\n                    public void call(Throwable throwable) {\n                        isInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());\n                    }\n                })\n                .materialize()\n                .toBlocking().single();\n\n        System.out.println(\"initialized = \" + HystrixRequestContext.isCurrentThreadInitialized());\n        System.out.println(\"initialized inside onError = \" + isInitialized.get());\n        assertEquals(true, isInitialized.get());\n    }\n\n    @Test\n    public void testNoRequestContextOnSimpleConcurencyStrategyWithoutException() throws Exception {\n        shutdownContextIfExists();\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.default.requestLog.enabled\", \"false\");\n\n        new SimpleCommand().execute();\n\n        assertTrue(\"We are able to run the simple command without a context initialization error.\", true);\n    }\n\n    private void shutdownContextIfExists() {\n        // instead of storing the reference from initialize we'll just get the current state and shutdown\n        if (HystrixRequestContext.getContextForCurrentThread() != null) {\n            // it could have been set NULL by the test\n            HystrixRequestContext.getContextForCurrentThread().shutdown();\n        }\n    }\n    private static class DummyHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {}\n\n  public static class TimeoutCommand extends HystrixCommand<Void> {\n        static final HystrixCommand.Setter properties = HystrixCommand.Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"TimeoutTest\"))\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionTimeoutInMilliseconds(50));\n\n        public TimeoutCommand() {\n            super(properties);\n        }\n\n        @Override\n        protected Void run() throws Exception {\n            Thread.sleep(500);\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/concurrency/HystrixContextSchedulerTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.concurrency;\n\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.Test;\n\nimport rx.Scheduler;\nimport rx.functions.Action0;\nimport rx.schedulers.Schedulers;\n\npublic class HystrixContextSchedulerTest {\n    \n    @Test(timeout = 2500)\n    public void testUnsubscribeWrappedScheduler() throws InterruptedException {\n        Scheduler s = Schedulers.newThread();\n        final AtomicBoolean interrupted = new AtomicBoolean();\n        final CountDownLatch start = new CountDownLatch(1);\n        final CountDownLatch end = new CountDownLatch(1);\n\n        HystrixContextScheduler hcs = new HystrixContextScheduler(s);\n\n        Scheduler.Worker w = hcs.createWorker();\n        try {\n            w.schedule(new Action0() {\n                @Override\n                public void call() {\n                    start.countDown();\n                    try {\n                        try {\n                            Thread.sleep(5000);\n                        } catch (InterruptedException ex) {\n                            interrupted.set(true);\n                        }\n                    } finally {\n                        end.countDown();\n                    }\n                }\n            });\n            \n            start.await();\n            \n            w.unsubscribe();\n            \n            end.await();\n            \n            assertTrue(interrupted.get());\n        } finally {\n            w.unsubscribe();\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/metrics/HystrixMetricsPublisherFactoryTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.metrics;\n\nimport static junit.framework.Assert.assertNotSame;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertSame;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.HystrixThreadPoolProperties;\n\npublic class HystrixMetricsPublisherFactoryTest {\n    @Before\n    public void reset() {\n        HystrixPlugins.reset();\n    }\n\n    /**\n     * Assert that we only call a publisher once for a given Command or ThreadPool key.\n     */\n    @Test\n    public void testSingleInitializePerKey() {\n        final TestHystrixMetricsPublisher publisher = new TestHystrixMetricsPublisher();\n        HystrixPlugins.getInstance().registerMetricsPublisher(publisher);\n        final HystrixMetricsPublisherFactory factory = new HystrixMetricsPublisherFactory();\n        ArrayList<Thread> threads = new ArrayList<Thread>();\n        for (int i = 0; i < 20; i++) {\n            threads.add(new Thread(new Runnable() {\n\n                @Override\n                public void run() {\n                    factory.getPublisherForCommand(TestCommandKey.TEST_A, null, null, null, null);\n                    factory.getPublisherForCommand(TestCommandKey.TEST_B, null, null, null, null);\n                    factory.getPublisherForThreadPool(TestThreadPoolKey.TEST_A, null, null);\n                }\n\n            }));\n        }\n\n        // start them\n        for (Thread t : threads) {\n            t.start();\n        }\n\n        // wait for them to finish\n        for (Thread t : threads) {\n            try {\n                t.join();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n\n        // we should see 2 commands and 1 threadPool publisher created\n        assertEquals(2, publisher.commandCounter.get());\n        assertEquals(1, publisher.threadCounter.get());\n    }\n\n    @Test\n    public void testMetricsPublisherReset() {\n        // precondition: HystrixMetricsPublisherFactory class is not loaded. Calling HystrixPlugins.reset() here should be good enough to run this with other tests.\n\n        // set first custom publisher\n        HystrixCommandKey key = HystrixCommandKey.Factory.asKey(\"key\");\n        HystrixMetricsPublisherCommand firstCommand = new HystrixMetricsPublisherCommandDefault(key, null, null, null, null);\n        HystrixMetricsPublisher firstPublisher = new CustomPublisher(firstCommand);\n        HystrixPlugins.getInstance().registerMetricsPublisher(firstPublisher);\n\n        // ensure that first custom publisher is used\n        HystrixMetricsPublisherCommand cmd = HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(key, null, null, null, null);\n        assertSame(firstCommand, cmd);\n\n        // reset, then change to second custom publisher\n        HystrixPlugins.reset();\n        HystrixMetricsPublisherCommand secondCommand = new HystrixMetricsPublisherCommandDefault(key, null, null, null, null);\n        HystrixMetricsPublisher secondPublisher = new CustomPublisher(secondCommand);\n        HystrixPlugins.getInstance().registerMetricsPublisher(secondPublisher);\n\n        // ensure that second custom publisher is used\n        cmd = HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(key, null, null, null, null);\n        assertNotSame(firstCommand, cmd);\n        assertSame(secondCommand, cmd);\n    }\n\n    private static class TestHystrixMetricsPublisher extends HystrixMetricsPublisher {\n\n        AtomicInteger commandCounter = new AtomicInteger();\n        AtomicInteger threadCounter = new AtomicInteger();\n\n        @Override\n        public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandOwner, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n            return new HystrixMetricsPublisherCommand() {\n                @Override\n                public void initialize() {\n                    commandCounter.incrementAndGet();\n                }\n            };\n        }\n\n        @Override\n        public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolMetrics metrics, HystrixThreadPoolProperties properties) {\n            return new HystrixMetricsPublisherThreadPool() {\n                @Override\n                public void initialize() {\n                    threadCounter.incrementAndGet();\n                }\n            };\n        }\n\n    }\n\n    private static enum TestCommandKey implements HystrixCommandKey {\n        TEST_A, TEST_B\n    }\n\n    private static enum TestThreadPoolKey implements HystrixThreadPoolKey {\n        TEST_A, TEST_B\n    }\n\n    static class CustomPublisher extends HystrixMetricsPublisher{\n        private HystrixMetricsPublisherCommand commandToReturn;\n        public CustomPublisher(HystrixMetricsPublisherCommand commandToReturn){\n            this.commandToReturn = commandToReturn;\n        }\n\n        @Override\n        public HystrixMetricsPublisherCommand getMetricsPublisherForCommand(HystrixCommandKey commandKey, HystrixCommandGroupKey commandGroupKey, HystrixCommandMetrics metrics, HystrixCircuitBreaker circuitBreaker, HystrixCommandProperties properties) {\n            return commandToReturn;\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/properties/HystrixPropertiesChainedArchaiusPropertyTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.After;\nimport org.junit.Test;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicBooleanProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicIntegerProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.DynamicStringProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.IntegerProperty;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedArchaiusProperty.StringProperty;\n\npublic class HystrixPropertiesChainedArchaiusPropertyTest {\n    @After\n    public void cleanUp() {\n        // Tests which use ConfigurationManager.getConfigInstance() will leave the singleton in an initialize state,\n        // this will leave the singleton in a reasonable state between tests.\n        ConfigurationManager.getConfigInstance().clear();\n    }\n\n    @Test\n    public void testString() throws Exception {\n\n        DynamicStringProperty pString = new DynamicStringProperty(\"defaultString\", \"default-default\");\n        HystrixPropertiesChainedArchaiusProperty.StringProperty fString = new HystrixPropertiesChainedArchaiusProperty.StringProperty(\"overrideString\", pString);\n\n        assertTrue(\"default-default\".equals(fString.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"defaultString\", \"default\");\n        assertTrue(\"default\".equals(fString.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"overrideString\", \"override\");\n        assertTrue(\"override\".equals(fString.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"overrideString\");\n        assertTrue(\"default\".equals(fString.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"defaultString\");\n        assertTrue(\"default-default\".equals(fString.get()));\n    }\n\n    @Test\n    public void testInteger() throws Exception {\n\n        DynamicIntegerProperty pInt = new DynamicIntegerProperty(\"defaultInt\", -1);\n        HystrixPropertiesChainedArchaiusProperty.IntegerProperty fInt = new HystrixPropertiesChainedArchaiusProperty.IntegerProperty(\"overrideInt\", pInt);\n\n        assertTrue(-1 == fInt.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"defaultInt\", 10);\n        assertTrue(10 == fInt.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"overrideInt\", 11);\n        assertTrue(11 == fInt.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"overrideInt\");\n        assertTrue(10 == fInt.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"defaultInt\");\n        assertTrue(-1 == fInt.get());\n    }\n\n    @Test\n    public void testBoolean() throws Exception {\n\n        DynamicBooleanProperty pBoolean = new DynamicBooleanProperty(\"defaultBoolean\", true);\n        HystrixPropertiesChainedArchaiusProperty.BooleanProperty fBoolean = new HystrixPropertiesChainedArchaiusProperty.BooleanProperty(\"overrideBoolean\", pBoolean);\n\n        System.out.println(\"pBoolean: \" + pBoolean.get());\n        System.out.println(\"fBoolean: \" + fBoolean.get());\n\n        assertTrue(fBoolean.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"defaultBoolean\", Boolean.FALSE);\n\n        System.out.println(\"pBoolean: \" + pBoolean.get());\n        System.out.println(\"fBoolean: \" + fBoolean.get());\n\n        assertFalse(fBoolean.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"overrideBoolean\", Boolean.TRUE);\n        assertTrue(fBoolean.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"overrideBoolean\");\n        assertFalse(fBoolean.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"defaultBoolean\");\n        assertTrue(fBoolean.get());\n    }\n\n    @Test\n    public void testChainingString() throws Exception {\n\n        DynamicStringProperty node1 = new DynamicStringProperty(\"node1\", \"v1\");\n        StringProperty node2 = new HystrixPropertiesChainedArchaiusProperty.StringProperty(\"node2\", node1);\n\n        HystrixPropertiesChainedArchaiusProperty.StringProperty node3 = new HystrixPropertiesChainedArchaiusProperty.StringProperty(\"node3\", node2);\n\n        assertTrue(\"\" + node3.get(), \"v1\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node1\", \"v11\");\n        assertTrue(\"v11\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", \"v22\");\n        assertTrue(\"v22\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node1\");\n        assertTrue(\"v22\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node3\", \"v33\");\n        assertTrue(\"v33\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node2\");\n        assertTrue(\"v33\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", \"v222\");\n        assertTrue(\"v33\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node3\");\n        assertTrue(\"v222\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node2\");\n        assertTrue(\"v1\".equals(node3.get()));\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", \"v2222\");\n        assertTrue(\"v2222\".equals(node3.get()));\n    }\n\n    @Test\n    public void testChainingInteger() throws Exception {\n\n        DynamicIntegerProperty node1 = new DynamicIntegerProperty(\"node1\", 1);\n        IntegerProperty node2 = new HystrixPropertiesChainedArchaiusProperty.IntegerProperty(\"node2\", node1);\n\n        HystrixPropertiesChainedArchaiusProperty.IntegerProperty node3 = new HystrixPropertiesChainedArchaiusProperty.IntegerProperty(\"node3\", node2);\n\n        assertTrue(\"\" + node3.get(), 1 == node3.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node1\", 11);\n        assertTrue(11 == node3.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", 22);\n        assertTrue(22 == node3.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node1\");\n        assertTrue(22 == node3.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node3\", 33);\n        assertTrue(33 == node3.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node2\");\n        assertTrue(33 == node3.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", 222);\n        assertTrue(33 == node3.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node3\");\n        assertTrue(222 == node3.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"node2\");\n        assertTrue(1 == node3.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"node2\", 2222);\n        assertTrue(2222 == node3.get());\n    }\n\n    @Test\n    public void testAddCallback() throws Exception {\n\n        final DynamicStringProperty node1 = new DynamicStringProperty(\"n1\", \"n1\");\n        final HystrixPropertiesChainedArchaiusProperty.StringProperty node2 = new HystrixPropertiesChainedArchaiusProperty.StringProperty(\"n2\", node1);\n\n        final AtomicInteger callbackCount = new AtomicInteger(0);\n\n        node2.addCallback(new Runnable() {\n            @Override\n            public void run() {\n                callbackCount.incrementAndGet();\n            }\n        });\n\n        assertTrue(0 == callbackCount.get());\n\n        assertTrue(\"n1\".equals(node2.get()));\n        assertTrue(0 == callbackCount.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"n1\", \"n11\");\n        assertTrue(\"n11\".equals(node2.get()));\n        assertTrue(0 == callbackCount.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"n2\", \"n22\");\n        assertTrue(\"n22\".equals(node2.get()));\n        assertTrue(1 == callbackCount.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"n1\");\n        assertTrue(\"n22\".equals(node2.get()));\n        assertTrue(1 == callbackCount.get());\n\n        ConfigurationManager.getConfigInstance().setProperty(\"n2\", \"n222\");\n        assertTrue(\"n222\".equals(node2.get()));\n        assertTrue(2 == callbackCount.get());\n\n        ConfigurationManager.getConfigInstance().clearProperty(\"n2\");\n        assertTrue(\"n1\".equals(node2.get()));\n        assertTrue(3 == callbackCount.get());\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/strategy/properties/HystrixPropertyTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.strategy.properties;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.strategy.properties.HystrixProperty.Factory;\n\npublic class HystrixPropertyTest {\n\n    @Test\n    public void testNested1() {\n        HystrixProperty<String> a = Factory.asProperty(\"a\");\n        assertEquals(\"a\", a.get());\n\n        HystrixProperty<String> aWithDefault = Factory.asProperty(a, \"b\");\n        assertEquals(\"a\", aWithDefault.get());\n    }\n\n    @Test\n    public void testNested2() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n\n        HystrixProperty<String> withDefault = Factory.asProperty(nullValue, \"b\");\n        assertEquals(\"b\", withDefault.get());\n    }\n\n    @Test\n    public void testNested3() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n        HystrixProperty<String> a = Factory.asProperty(nullValue, \"a\");\n\n        HystrixProperty<String> withDefault = Factory.asProperty(a, \"b\");\n        assertEquals(\"a\", withDefault.get());\n    }\n\n    @Test\n    public void testNested4() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n        HystrixProperty<String> a = Factory.asProperty(nullValue, null);\n\n        HystrixProperty<String> withDefault = Factory.asProperty(a, \"b\");\n        assertEquals(\"b\", withDefault.get());\n    }\n\n    @Test\n    public void testNested5() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n        HystrixProperty<String> a = Factory.asProperty(nullValue, null);\n\n        @SuppressWarnings(\"unchecked\")\n        HystrixProperty<String> withDefault = Factory.asProperty(a, Factory.asProperty(\"b\"));\n        assertEquals(\"b\", withDefault.get());\n    }\n\n    @Test\n    public void testSeries1() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n        HystrixProperty<String> a = Factory.asProperty(nullValue, null);\n\n        @SuppressWarnings(\"unchecked\")\n        HystrixProperty<String> withDefault = Factory.asProperty(a, nullValue, nullValue, Factory.asProperty(\"b\"));\n        assertEquals(\"b\", withDefault.get());\n    }\n\n    @Test\n    public void testSeries2() {\n        HystrixProperty<String> nullValue = Factory.nullProperty();\n        HystrixProperty<String> a = Factory.asProperty(nullValue, null);\n\n        @SuppressWarnings(\"unchecked\")\n        HystrixProperty<String> withDefault = Factory.asProperty(a, nullValue, Factory.asProperty(\"b\"), nullValue, Factory.asProperty(\"c\"));\n        assertEquals(\"b\", withDefault.get());\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/util/ExceptionsTest.java",
    "content": "package com.netflix.hystrix.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.io.IOException;\n\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\npublic class ExceptionsTest {\n\n    @Test\n    public void testCastOfException(){\n        Exception exception = new IOException(\"simulated checked exception message\");\n        try{\n            Exceptions.sneakyThrow(exception);\n            fail();\n        } catch(Exception e){\n            assertTrue(e instanceof  IOException);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixRollingNumberTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.util.HystrixRollingNumber.Time;\n\npublic class HystrixRollingNumberTest {\n\n    @Test\n    public void testCreatesBuckets() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n            // confirm the initial settings\n            assertEquals(200, counter.timeInMilliseconds);\n            assertEquals(10, counter.numberOfBuckets);\n            assertEquals(20, counter.bucketSizeInMillseconds);\n\n            // we start out with 0 buckets in the queue\n            assertEquals(0, counter.buckets.size());\n\n            // add a success in each interval which should result in all 10 buckets being created with 1 success in each\n            for (int i = 0; i < counter.numberOfBuckets; i++) {\n                counter.increment(HystrixRollingNumberEvent.SUCCESS);\n                time.increment(counter.bucketSizeInMillseconds);\n            }\n\n            // confirm we have all 10 buckets\n            assertEquals(10, counter.buckets.size());\n\n            // add 1 more and we should still only have 10 buckets since that's the max\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            assertEquals(10, counter.buckets.size());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testResetBuckets() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // we start out with 0 buckets in the queue\n            assertEquals(0, counter.buckets.size());\n\n            // add 1\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // confirm we have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // confirm we still have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // add 1\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // we should now have a single bucket with no values in it instead of 2 or more buckets\n            assertEquals(1, counter.buckets.size());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testEmptyBucketsFillIn() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // add 1\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // wait past 3 bucket time periods (the 1st bucket then 2 empty ones)\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // add another\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // we should have 4 (1 + 2 empty + 1 new one) buckets\n            assertEquals(4, counter.buckets.size());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testIncrementInSingleBucket() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 4\n            assertEquals(4, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.SUCCESS).sum());\n            assertEquals(2, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.FAILURE).sum());\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.TIMEOUT).sum());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testTimeout() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 1\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.TIMEOUT).sum());\n            assertEquals(1, counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT));\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // incremenet again in latest bucket\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the counts of the last bucket\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.TIMEOUT).sum());\n\n            // the total counts\n            assertEquals(2, counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testShortCircuited() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SHORT_CIRCUITED);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 1\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.SHORT_CIRCUITED).sum());\n            assertEquals(1, counter.getRollingSum(HystrixRollingNumberEvent.SHORT_CIRCUITED));\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // incremenet again in latest bucket\n            counter.increment(HystrixRollingNumberEvent.SHORT_CIRCUITED);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the counts of the last bucket\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.SHORT_CIRCUITED).sum());\n\n            // the total counts\n            assertEquals(2, counter.getRollingSum(HystrixRollingNumberEvent.SHORT_CIRCUITED));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testThreadPoolRejection() {\n        testCounterType(HystrixRollingNumberEvent.THREAD_POOL_REJECTED);\n    }\n\n    @Test\n    public void testFallbackSuccess() {\n        testCounterType(HystrixRollingNumberEvent.FALLBACK_SUCCESS);\n    }\n\n    @Test\n    public void testFallbackFailure() {\n        testCounterType(HystrixRollingNumberEvent.FALLBACK_FAILURE);\n    }\n\n    @Test\n    public void testExceptionThrow() {\n        testCounterType(HystrixRollingNumberEvent.EXCEPTION_THROWN);\n    }\n\n    private void testCounterType(HystrixRollingNumberEvent type) {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(type);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 1\n            assertEquals(1, counter.buckets.getLast().getAdder(type).sum());\n            assertEquals(1, counter.getRollingSum(type));\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // increment again in latest bucket\n            counter.increment(type);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the counts of the last bucket\n            assertEquals(1, counter.buckets.getLast().getAdder(type).sum());\n\n            // the total counts\n            assertEquals(2, counter.getRollingSum(type));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testIncrementInMultipleBuckets() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n            counter.increment(HystrixRollingNumberEvent.SHORT_CIRCUITED);\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.TIMEOUT);\n            counter.increment(HystrixRollingNumberEvent.SHORT_CIRCUITED);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the counts of the last bucket\n            assertEquals(2, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.SUCCESS).sum());\n            assertEquals(3, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.FAILURE).sum());\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.TIMEOUT).sum());\n            assertEquals(1, counter.buckets.getLast().getAdder(HystrixRollingNumberEvent.SHORT_CIRCUITED).sum());\n\n            // the total counts\n            assertEquals(6, counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS));\n            assertEquals(5, counter.getRollingSum(HystrixRollingNumberEvent.FAILURE));\n            assertEquals(3, counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT));\n            assertEquals(2, counter.getRollingSum(HystrixRollingNumberEvent.SHORT_CIRCUITED));\n\n            // wait until window passes\n            time.increment(counter.timeInMilliseconds);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // the total counts should now include only the last bucket after a reset since the window passed\n            assertEquals(1, counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS));\n            assertEquals(0, counter.getRollingSum(HystrixRollingNumberEvent.FAILURE));\n            assertEquals(0, counter.getRollingSum(HystrixRollingNumberEvent.TIMEOUT));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testCounterRetrievalRefreshesBuckets() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n            counter.increment(HystrixRollingNumberEvent.FAILURE);\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // we should have 1 bucket since nothing has triggered the update of buckets in the elapsed time\n            assertEquals(1, counter.buckets.size());\n\n            // the total counts\n            assertEquals(4, counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS));\n            assertEquals(2, counter.getRollingSum(HystrixRollingNumberEvent.FAILURE));\n\n            // we should have 4 buckets as the counter 'gets' should have triggered the buckets being created to fill in time\n            assertEquals(4, counter.buckets.size());\n\n            // wait until window passes\n            time.increment(counter.timeInMilliseconds);\n\n            // the total counts should all be 0 (and the buckets cleared by the get, not only increment)\n            assertEquals(0, counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS));\n            assertEquals(0, counter.getRollingSum(HystrixRollingNumberEvent.FAILURE));\n\n            // increment\n            counter.increment(HystrixRollingNumberEvent.SUCCESS);\n\n            // the total counts should now include only the last bucket after a reset since the window passed\n            assertEquals(1, counter.getRollingSum(HystrixRollingNumberEvent.SUCCESS));\n            assertEquals(0, counter.getRollingSum(HystrixRollingNumberEvent.FAILURE));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUpdateMax1() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 10);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 10\n            assertEquals(10, counter.buckets.getLast().getMaxUpdater(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE).max());\n            assertEquals(10, counter.getRollingMaxValue(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE));\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            // increment again in latest bucket\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 20);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the max\n            assertEquals(20, counter.buckets.getLast().getMaxUpdater(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE).max());\n\n            // counts per bucket\n            long values[] = counter.getValues(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE);\n            assertEquals(10, values[0]); // oldest bucket\n            assertEquals(0, values[1]);\n            assertEquals(0, values[2]);\n            assertEquals(20, values[3]); // latest bucket\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUpdateMax2() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            // increment\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 10);\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 30);\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 20);\n\n            // we should have 1 bucket\n            assertEquals(1, counter.buckets.size());\n\n            // the count should be 30\n            assertEquals(30, counter.buckets.getLast().getMaxUpdater(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE).max());\n            assertEquals(30, counter.getRollingMaxValue(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE));\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds * 3);\n\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 30);\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 30);\n            counter.updateRollingMax(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE, 50);\n\n            // we should have 4 buckets\n            assertEquals(4, counter.buckets.size());\n\n            // the count\n            assertEquals(50, counter.buckets.getLast().getMaxUpdater(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE).max());\n            assertEquals(50, counter.getValueOfLatestBucket(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE));\n\n            // values per bucket\n            long values[] = counter.getValues(HystrixRollingNumberEvent.THREAD_MAX_ACTIVE);\n            assertEquals(30, values[0]); // oldest bucket\n            assertEquals(0, values[1]);\n            assertEquals(0, values[2]);\n            assertEquals(50, values[3]); // latest bucket\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testMaxValue() {\n        MockedTime time = new MockedTime();\n        try {\n            HystrixRollingNumberEvent type = HystrixRollingNumberEvent.THREAD_MAX_ACTIVE;\n\n            HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n\n            counter.updateRollingMax(type, 10);\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds);\n\n            counter.updateRollingMax(type, 30);\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds);\n\n            counter.updateRollingMax(type, 40);\n\n            // sleep to get to a new bucket\n            time.increment(counter.bucketSizeInMillseconds);\n\n            counter.updateRollingMax(type, 15);\n\n            assertEquals(40, counter.getRollingMaxValue(type));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(\"Exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testEmptySum() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.COLLAPSED;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n        assertEquals(0, counter.getRollingSum(type));\n    }\n\n    @Test\n    public void testEmptyMax() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.THREAD_MAX_ACTIVE;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n        assertEquals(0, counter.getRollingMaxValue(type));\n    }\n\n    @Test\n    public void testEmptyLatestValue() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.THREAD_MAX_ACTIVE;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 200, 10);\n        assertEquals(0, counter.getValueOfLatestBucket(type));\n    }\n\n    @Test\n    public void testRolling() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.THREAD_MAX_ACTIVE;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 20, 2);\n        // iterate over 20 buckets on a queue sized for 2\n        for (int i = 0; i < 20; i++) {\n            // first bucket\n            counter.getCurrentBucket();\n            try {\n                time.increment(counter.bucketSizeInMillseconds);\n            } catch (Exception e) {\n                // ignore\n            }\n\n            assertEquals(2, counter.getValues(type).length);\n\n            counter.getValueOfLatestBucket(type);\n\n            // System.out.println(\"Head: \" + counter.buckets.state.get().head);\n            // System.out.println(\"Tail: \" + counter.buckets.state.get().tail);\n        }\n    }\n\n    @Test\n    public void testCumulativeCounterAfterRolling() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.SUCCESS;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 20, 2);\n\n        assertEquals(0, counter.getCumulativeSum(type));\n\n        // iterate over 20 buckets on a queue sized for 2\n        for (int i = 0; i < 20; i++) {\n            // first bucket\n            counter.increment(type);\n            try {\n                time.increment(counter.bucketSizeInMillseconds);\n            } catch (Exception e) {\n                // ignore\n            }\n\n            assertEquals(2, counter.getValues(type).length);\n\n            counter.getValueOfLatestBucket(type);\n\n        }\n\n        // cumulative count should be 20 (for the number of loops above) regardless of buckets rolling\n        assertEquals(20, counter.getCumulativeSum(type));\n    }\n\n    @Test\n    public void testCumulativeCounterAfterRollingAndReset() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.SUCCESS;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 20, 2);\n\n        assertEquals(0, counter.getCumulativeSum(type));\n\n        // iterate over 20 buckets on a queue sized for 2\n        for (int i = 0; i < 20; i++) {\n            // first bucket\n            counter.increment(type);\n            try {\n                time.increment(counter.bucketSizeInMillseconds);\n            } catch (Exception e) {\n                // ignore\n            }\n\n            assertEquals(2, counter.getValues(type).length);\n\n            counter.getValueOfLatestBucket(type);\n\n            if (i == 5 || i == 15) {\n                // simulate a reset occurring every once in a while\n                // so we ensure the absolute sum is handling it okay\n                counter.reset();\n            }\n        }\n\n        // cumulative count should be 20 (for the number of loops above) regardless of buckets rolling\n        assertEquals(20, counter.getCumulativeSum(type));\n    }\n\n    @Test\n    public void testCumulativeCounterAfterRollingAndReset2() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.SUCCESS;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 20, 2);\n\n        assertEquals(0, counter.getCumulativeSum(type));\n\n        counter.increment(type);\n        counter.increment(type);\n        counter.increment(type);\n\n        // iterate over 20 buckets on a queue sized for 2\n        for (int i = 0; i < 20; i++) {\n            try {\n                time.increment(counter.bucketSizeInMillseconds);\n            } catch (Exception e) {\n                // ignore\n            }\n\n            if (i == 5 || i == 15) {\n                // simulate a reset occurring every once in a while\n                // so we ensure the absolute sum is handling it okay\n                counter.reset();\n            }\n        }\n\n        // no increments during the loop, just some before and after\n        counter.increment(type);\n        counter.increment(type);\n\n        // cumulative count should be 5 regardless of buckets rolling\n        assertEquals(5, counter.getCumulativeSum(type));\n    }\n\n    @Test\n    public void testCumulativeCounterAfterRollingAndReset3() {\n        MockedTime time = new MockedTime();\n        HystrixRollingNumberEvent type = HystrixRollingNumberEvent.SUCCESS;\n        HystrixRollingNumber counter = new HystrixRollingNumber(time, 20, 2);\n\n        assertEquals(0, counter.getCumulativeSum(type));\n\n        counter.increment(type);\n        counter.increment(type);\n        counter.increment(type);\n\n        // iterate over 20 buckets on a queue sized for 2\n        for (int i = 0; i < 20; i++) {\n            try {\n                time.increment(counter.bucketSizeInMillseconds);\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n\n        // since we are rolling over the buckets it should reset naturally\n\n        // no increments during the loop, just some before and after\n        counter.increment(type);\n        counter.increment(type);\n\n        // cumulative count should be 5 regardless of buckets rolling\n        assertEquals(5, counter.getCumulativeSum(type));\n    }\n\n    private static class MockedTime implements Time {\n\n        private AtomicInteger time = new AtomicInteger(0);\n\n        @Override\n        public long getCurrentTimeInMillis() {\n            return time.get();\n        }\n\n        public void increment(int millis) {\n            time.addAndGet(millis);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixRollingPercentileTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport com.netflix.hystrix.strategy.properties.HystrixProperty;\nimport com.netflix.hystrix.util.HystrixRollingPercentile.PercentileSnapshot;\nimport com.netflix.hystrix.util.HystrixRollingPercentile.Time;\n\npublic class HystrixRollingPercentileTest {\n\n    private static final int timeInMilliseconds = 60000;\n    private static final int numberOfBuckets = 12; // 12 buckets at 5000ms each\n    private static final int bucketDataLength = 1000;\n    private static final HystrixProperty<Boolean> enabled = HystrixProperty.Factory.asProperty(true);\n\n    private static ExecutorService threadPool;\n\n    @BeforeClass\n    public static void setUp() {\n        threadPool = Executors.newFixedThreadPool(10);\n    }\n\n    @AfterClass\n    public static void tearDown() {\n        threadPool.shutdown();\n        try {\n            threadPool.awaitTermination(10, TimeUnit.SECONDS);\n        } catch (InterruptedException ie) {\n            System.out.println(\"Thread pool never terminated in HystrixRollingPercentileTest\");\n        }\n    }\n\n    @Test\n    public void testRolling() {\n        MockedTime time = new MockedTime();\n        HystrixRollingPercentile p = new HystrixRollingPercentile(time, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);\n        p.addValue(1000);\n        p.addValue(1000);\n        p.addValue(1000);\n        p.addValue(2000);\n\n        assertEquals(1, p.buckets.size());\n\n        // no bucket turnover yet so percentile not yet generated\n        assertEquals(0, p.getPercentile(50));\n\n        time.increment(6000);\n\n        // still only 1 bucket until we touch it again\n        assertEquals(1, p.buckets.size());\n\n        // a bucket has been created so we have a new percentile\n        assertEquals(1000, p.getPercentile(50));\n\n        // now 2 buckets since getting a percentile causes bucket retrieval\n        assertEquals(2, p.buckets.size());\n\n        p.addValue(1000);\n        p.addValue(500);\n\n        // should still be 2 buckets\n        assertEquals(2, p.buckets.size());\n\n        p.addValue(200);\n        p.addValue(200);\n        p.addValue(1600);\n        p.addValue(200);\n        p.addValue(1600);\n        p.addValue(1600);\n\n        // we haven't progressed to a new bucket so the percentile should be the same and ignore the most recent bucket\n        assertEquals(1000, p.getPercentile(50));\n\n        // increment to another bucket so we include all of the above in the PercentileSnapshot\n        time.increment(6000);\n\n        // the rolling version should have the same data as creating a snapshot like this\n        PercentileSnapshot ps = new PercentileSnapshot(1000, 1000, 1000, 2000, 1000, 500, 200, 200, 1600, 200, 1600, 1600);\n\n        assertEquals(ps.getPercentile(0.15), p.getPercentile(0.15));\n        assertEquals(ps.getPercentile(0.50), p.getPercentile(0.50));\n        assertEquals(ps.getPercentile(0.90), p.getPercentile(0.90));\n        assertEquals(ps.getPercentile(0.995), p.getPercentile(0.995));\n\n        System.out.println(\"100th: \" + ps.getPercentile(100) + \"  \" + p.getPercentile(100));\n        System.out.println(\"99.5th: \" + ps.getPercentile(99.5) + \"  \" + p.getPercentile(99.5));\n        System.out.println(\"99th: \" + ps.getPercentile(99) + \"  \" + p.getPercentile(99));\n        System.out.println(\"90th: \" + ps.getPercentile(90) + \"  \" + p.getPercentile(90));\n        System.out.println(\"50th: \" + ps.getPercentile(50) + \"  \" + p.getPercentile(50));\n        System.out.println(\"10th: \" + ps.getPercentile(10) + \"  \" + p.getPercentile(10));\n\n        // mean = 1000+1000+1000+2000+1000+500+200+200+1600+200+1600+1600/12\n        assertEquals(991, ps.getMean());\n    }\n\n    @Test\n    public void testValueIsZeroAfterRollingWindowPassesAndNoTraffic() {\n        MockedTime time = new MockedTime();\n        HystrixRollingPercentile p = new HystrixRollingPercentile(time, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);\n        p.addValue(1000);\n        p.addValue(1000);\n        p.addValue(1000);\n        p.addValue(2000);\n        p.addValue(4000);\n\n        assertEquals(1, p.buckets.size());\n\n        // no bucket turnover yet so percentile not yet generated\n        assertEquals(0, p.getPercentile(50));\n\n        time.increment(6000);\n\n        // still only 1 bucket until we touch it again\n        assertEquals(1, p.buckets.size());\n\n        // a bucket has been created so we have a new percentile\n        assertEquals(1500, p.getPercentile(50));\n\n        // let 1 minute pass\n        time.increment(60000);\n\n        // no data in a minute should mean all buckets are empty (or reset) so we should not have any percentiles\n        assertEquals(0, p.getPercentile(50));\n    }\n\n    @Test\n    public void testSampleDataOverTime1() {\n        System.out.println(\"\\n\\n***************************** testSampleDataOverTime1 \\n\");\n\n        MockedTime time = new MockedTime();\n        HystrixRollingPercentile p = new HystrixRollingPercentile(time, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);\n        int previousTime = 0;\n        for (int i = 0; i < SampleDataHolder1.data.length; i++) {\n            int timeInMillisecondsSinceStart = SampleDataHolder1.data[i][0];\n            int latency = SampleDataHolder1.data[i][1];\n            time.increment(timeInMillisecondsSinceStart - previousTime);\n            previousTime = timeInMillisecondsSinceStart;\n            p.addValue(latency);\n        }\n\n        System.out.println(\"0.01: \" + p.getPercentile(0.01));\n        System.out.println(\"Median: \" + p.getPercentile(50));\n        System.out.println(\"90th: \" + p.getPercentile(90));\n        System.out.println(\"99th: \" + p.getPercentile(99));\n        System.out.println(\"99.5th: \" + p.getPercentile(99.5));\n        System.out.println(\"99.99: \" + p.getPercentile(99.99));\n\n        System.out.println(\"Median: \" + p.getPercentile(50));\n        System.out.println(\"Median: \" + p.getPercentile(50));\n        System.out.println(\"Median: \" + p.getPercentile(50));\n\n        /*\n         * In a loop as a use case was found where very different values were calculated in subsequent requests.\n         */\n        for (int i = 0; i < 10; i++) {\n            if (p.getPercentile(50) > 5) {\n                fail(\"We expect around 2 but got: \" + p.getPercentile(50));\n            }\n\n            if (p.getPercentile(99.5) < 20) {\n                fail(\"We expect to see some high values over 20 but got: \" + p.getPercentile(99.5));\n            }\n        }\n    }\n\n    @Test\n    public void testSampleDataOverTime2() {\n        System.out.println(\"\\n\\n***************************** testSampleDataOverTime2 \\n\");\n        MockedTime time = new MockedTime();\n        int previousTime = 0;\n        HystrixRollingPercentile p = new HystrixRollingPercentile(time, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);\n        for (int i = 0; i < SampleDataHolder2.data.length; i++) {\n            int timeInMillisecondsSinceStart = SampleDataHolder2.data[i][0];\n            int latency = SampleDataHolder2.data[i][1];\n            time.increment(timeInMillisecondsSinceStart - previousTime);\n            previousTime = timeInMillisecondsSinceStart;\n            p.addValue(latency);\n        }\n\n        System.out.println(\"0.01: \" + p.getPercentile(0.01));\n        System.out.println(\"Median: \" + p.getPercentile(50));\n        System.out.println(\"90th: \" + p.getPercentile(90));\n        System.out.println(\"99th: \" + p.getPercentile(99));\n        System.out.println(\"99.5th: \" + p.getPercentile(99.5));\n        System.out.println(\"99.99: \" + p.getPercentile(99.99));\n\n        if (p.getPercentile(50) > 90 || p.getPercentile(50) < 50) {\n            fail(\"We expect around 60-70 but got: \" + p.getPercentile(50));\n        }\n\n        if (p.getPercentile(99) < 400) {\n            fail(\"We expect to see some high values over 400 but got: \" + p.getPercentile(99));\n        }\n    }\n\n    public PercentileSnapshot getPercentileForValues(int... values) {\n        return new PercentileSnapshot(values);\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Median1() {\n        PercentileSnapshot list = new PercentileSnapshot(100, 100, 100, 100, 200, 200, 200, 300, 300, 300, 300);\n        Assert.assertEquals(200, list.getPercentile(50));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Median2() {\n        PercentileSnapshot list = new PercentileSnapshot(100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 500);\n        Assert.assertEquals(100, list.getPercentile(50));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Median3() {\n        PercentileSnapshot list = new PercentileSnapshot(50, 75, 100, 125, 160, 170, 180, 200, 210, 300, 500);\n        //            list.addValue(50); // 1\n        //            list.addValue(75); // 2\n        //            list.addValue(100); // 3\n        //            list.addValue(125); // 4\n        //            list.addValue(160); // 5\n        //            list.addValue(170); // 6 \n        //            list.addValue(180); // 7\n        //            list.addValue(200); // 8\n        //            list.addValue(210); // 9\n        //            list.addValue(300); // 10\n        //            list.addValue(500); // 11\n\n        Assert.assertEquals(175, list.getPercentile(50));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Median4() {\n        PercentileSnapshot list = new PercentileSnapshot(300, 75, 125, 500, 100, 160, 180, 200, 210, 50, 170);\n        // unsorted so it is expected to sort it for us\n        //            list.addValue(300); // 10\n        //            list.addValue(75); // 2\n        //            list.addValue(125); // 4\n        //            list.addValue(500); // 11\n        //            list.addValue(100); // 3\n        //            list.addValue(160); // 5\n        //            list.addValue(180); // 7\n        //            list.addValue(200); // 8\n        //            list.addValue(210); // 9\n        //            list.addValue(50); // 1\n        //            list.addValue(170); // 6 \n\n        Assert.assertEquals(175, list.getPercentile(50));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Extremes() {\n        PercentileSnapshot p = new PercentileSnapshot(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 800, 768, 657, 700, 867);\n\n        System.out.println(\"0.01: \" + p.getPercentile(0.01));\n        System.out.println(\"10th: \" + p.getPercentile(10));\n        System.out.println(\"Median: \" + p.getPercentile(50));\n        System.out.println(\"75th: \" + p.getPercentile(75));\n        System.out.println(\"90th: \" + p.getPercentile(90));\n        System.out.println(\"99th: \" + p.getPercentile(99));\n        System.out.println(\"99.5th: \" + p.getPercentile(99.5));\n        System.out.println(\"99.99: \" + p.getPercentile(99.99));\n        Assert.assertEquals(2, p.getPercentile(50));\n        Assert.assertEquals(2, p.getPercentile(10));\n        Assert.assertEquals(2, p.getPercentile(75));\n        if (p.getPercentile(95) < 600) {\n            fail(\"We expect the 90th to be over 600 to show the extremes but got: \" + p.getPercentile(90));\n        }\n        if (p.getPercentile(99) < 600) {\n            fail(\"We expect the 99th to be over 600 to show the extremes but got: \" + p.getPercentile(99));\n        }\n    }\n\n    @Test\n    public void testPercentileAlgorithm_HighPercentile() {\n        PercentileSnapshot p = getPercentileForValues(1, 2, 3);\n        Assert.assertEquals(2, p.getPercentile(50));\n        Assert.assertEquals(3, p.getPercentile(75));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_LowPercentile() {\n        PercentileSnapshot p = getPercentileForValues(1, 2);\n        Assert.assertEquals(1, p.getPercentile(25));\n        Assert.assertEquals(2, p.getPercentile(75));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_Percentiles() {\n        PercentileSnapshot p = getPercentileForValues(10, 30, 20, 40);\n        Assert.assertEquals(22, p.getPercentile(30), 1.0e-5);\n        Assert.assertEquals(20, p.getPercentile(25), 1.0e-5);\n        Assert.assertEquals(40, p.getPercentile(75), 1.0e-5);\n        Assert.assertEquals(30, p.getPercentile(50), 1.0e-5);\n\n        // invalid percentiles\n        Assert.assertEquals(10, p.getPercentile(-1));\n        Assert.assertEquals(40, p.getPercentile(101));\n    }\n\n    @Test\n    public void testPercentileAlgorithm_NISTExample() {\n        PercentileSnapshot p = getPercentileForValues(951772, 951567, 951937, 951959, 951442, 950610, 951591, 951195, 951772, 950925, 951990, 951682);\n        Assert.assertEquals(951983, p.getPercentile(90));\n        Assert.assertEquals(951990, p.getPercentile(100));\n    }\n\n    /**\n     * This code should work without throwing exceptions but the data returned will all be -1 since the rolling percentile is disabled.\n     */\n    @Test\n    public void testDoesNothingWhenDisabled() {\n        MockedTime time = new MockedTime();\n        int previousTime = 0;\n        HystrixRollingPercentile p = new HystrixRollingPercentile(time, timeInMilliseconds, numberOfBuckets, bucketDataLength, HystrixProperty.Factory.asProperty(false));\n        for (int i = 0; i < SampleDataHolder2.data.length; i++) {\n            int timeInMillisecondsSinceStart = SampleDataHolder2.data[i][0];\n            int latency = SampleDataHolder2.data[i][1];\n            time.increment(timeInMillisecondsSinceStart - previousTime);\n            previousTime = timeInMillisecondsSinceStart;\n            p.addValue(latency);\n        }\n\n        assertEquals(-1, p.getPercentile(50));\n        assertEquals(-1, p.getPercentile(75));\n        assertEquals(-1, p.getMean());\n    }\n\n    @Test\n    public void testThreadSafety() {\n        final MockedTime time = new MockedTime();\n        final HystrixRollingPercentile p = new HystrixRollingPercentile(time, 100, 25, 1000, HystrixProperty.Factory.asProperty(true));\n\n        final int NUM_THREADS = 1000;\n        final int NUM_ITERATIONS = 1000000;\n\n        final CountDownLatch latch = new CountDownLatch(NUM_THREADS);\n\n        final AtomicInteger aggregateMetrics = new AtomicInteger(); //same as a blackhole\n\n        final Random r = new Random();\n\n        Future<?> metricsPoller = threadPool.submit(new Runnable() {\n            @Override\n            public void run() {\n                while (!Thread.currentThread().isInterrupted()) {\n                    aggregateMetrics.addAndGet(p.getMean() + p.getPercentile(10) + p.getPercentile(50) + p.getPercentile(90));\n                    //System.out.println(\"AGGREGATE : \" + p.getPercentile(10) + \" : \" + p.getPercentile(50) + \" : \" + p.getPercentile(90));\n                }\n            }\n        });\n\n        for (int i = 0; i < NUM_THREADS; i++) {\n            final int threadId = i;\n            threadPool.submit(new Runnable() {\n                @Override\n                public void run() {\n                    for (int j = 1; j < NUM_ITERATIONS / NUM_THREADS + 1; j++) {\n                        int nextInt = r.nextInt(100);\n                        p.addValue(nextInt);\n                        if (threadId == 0) {\n                            time.increment(1);\n                        }\n                    }\n                    latch.countDown();\n                }\n            });\n        }\n\n        try {\n            latch.await(100, TimeUnit.SECONDS);\n            metricsPoller.cancel(true);\n        } catch (InterruptedException ex) {\n            fail(\"Timeout on all threads writing percentiles\");\n        }\n\n        aggregateMetrics.addAndGet(p.getMean() + p.getPercentile(10) + p.getPercentile(50) + p.getPercentile(90));\n        System.out.println(p.getMean() + \" : \" + p.getPercentile(50) + \" : \" + p.getPercentile(75) + \" : \" + p.getPercentile(90) + \" : \" + p.getPercentile(95) + \" : \" + p.getPercentile(99));\n    }\n\n    @Test\n    public void testWriteThreadSafety() {\n        final MockedTime time = new MockedTime();\n        final HystrixRollingPercentile p = new HystrixRollingPercentile(time, 100, 25, 1000, HystrixProperty.Factory.asProperty(true));\n\n        final int NUM_THREADS = 10;\n        final int NUM_ITERATIONS = 1000;\n\n        final CountDownLatch latch = new CountDownLatch(NUM_THREADS);\n\n        final Random r = new Random();\n\n        final AtomicInteger added = new AtomicInteger(0);\n\n        for (int i = 0; i < NUM_THREADS; i++) {\n            threadPool.submit(new Runnable() {\n                @Override\n                public void run() {\n                    for (int j = 1; j < NUM_ITERATIONS / NUM_THREADS + 1; j++) {\n                        int nextInt = r.nextInt(100);\n                        p.addValue(nextInt);\n                        added.getAndIncrement();\n                    }\n                    latch.countDown();\n                }\n            });\n        }\n\n        try {\n            latch.await(100, TimeUnit.SECONDS);\n            assertEquals(added.get(), p.buckets.peekLast().data.length());\n        } catch (InterruptedException ex) {\n            fail(\"Timeout on all threads writing percentiles\");\n        }\n    }\n\n    @Test\n    public void testThreadSafetyMulti() {\n        for (int i = 0; i < 100; i++) {\n            testThreadSafety();\n        }\n    }\n\n\n    private static class MockedTime implements Time {\n\n        private AtomicInteger time = new AtomicInteger(0);\n\n        @Override\n        public long getCurrentTimeInMillis() {\n            return time.get();\n        }\n\n        public void increment(int millis) {\n            time.addAndGet(millis);\n        }\n\n    }\n\n    /* sub-class to avoid 65k limit of a single class */\n    private static class SampleDataHolder1 {\n        /*\n         * Array of [milliseconds, latency]\n         */\n        private static int[][] data = new int[][] {\n                { 0, 3 }, { 43, 33 }, { 45, 11 }, { 45, 1 }, { 68, 13 }, { 88, 10 }, { 158, 2 }, { 158, 4 }, { 169, 12 }, { 267, 2 }, { 342, 2 }, { 438, 2 }, { 464, 7 }, { 504, 2 }, { 541, 6 }, { 541, 2 }, { 562, 2 }, { 581, 3 }, { 636, 2 }, { 778, 2 }, { 825, 1 }, { 859, 2 }, { 948, 1 }, { 1043, 2 }, { 1145, 2 }, { 1152, 1 }, { 1218, 5 },\n                { 1229, 2 }, { 1259, 2 }, { 1333, 2 }, { 1349, 2 }, { 1392, 2 }, { 1468, 1 }, { 1551, 2 }, { 1586, 2 }, { 1685, 2 }, { 1696, 1 }, { 1807, 2 }, { 1817, 3 }, { 1817, 6 }, { 1847, 2 }, { 1870, 2 }, { 1939, 2 }, { 2050, 2 }, { 2129, 3 }, { 2141, 2 }, { 2265, 2 }, { 2414, 1 }, { 2693, 2 }, { 2703, 2 }, { 2791, 2 }, { 2838, 2 },\n                { 2906, 2 }, { 2981, 2 }, { 3008, 2 }, { 3026, 4 }, { 3077, 2 }, { 3273, 2 }, { 3282, 2 }, { 3286, 2 }, { 3318, 3 }, { 3335, 5 }, { 3710, 2 }, { 3711, 1 }, { 3745, 2 }, { 3748, 4 }, { 3767, 3 }, { 3809, 3 }, { 3835, 35 }, { 4083, 1 }, { 4116, 2 }, { 4117, 1 }, { 4157, 1 }, { 4279, 2 }, { 4344, 2 }, { 4452, 2 }, { 4530, 2 },\n                { 4583, 2 }, { 4647, 3 }, { 4758, 2 }, { 4776, 2 }, { 4793, 2 }, { 4901, 2 }, { 4909, 2 }, { 4962, 2 }, { 4984, 2 }, { 5022, 2 }, { 5139, 2 }, { 5166, 1 }, { 5174, 2 }, { 5187, 2 }, { 5225, 2 }, { 5234, 2 }, { 5263, 1 }, { 5325, 2 }, { 5355, 4 }, { 5407, 1 }, { 5414, 2 }, { 5589, 2 }, { 5595, 2 }, { 5747, 2 }, { 5780, 2 },\n                { 5788, 2 }, { 5796, 2 }, { 5818, 2 }, { 5975, 1 }, { 6018, 1 }, { 6270, 2 }, { 6272, 2 }, { 6348, 2 }, { 6372, 2 }, { 6379, 2 }, { 6439, 2 }, { 6442, 2 }, { 6460, 2 }, { 6460, 2 }, { 6509, 2 }, { 6511, 1 }, { 6514, 4 }, { 6530, 8 }, { 6719, 2 }, { 6760, 2 }, { 6784, 2 }, { 6838, 1 }, { 6861, 2 }, { 6947, 2 }, { 7013, 2 },\n                { 7075, 2 }, { 7122, 5 }, { 7130, 2 }, { 7209, 3 }, { 7259, 2 }, { 7309, 1 }, { 7315, 3 }, { 7322, 2 }, { 7348, 2 }, { 7420, 2 }, { 7461, 2 }, { 7545, 2 }, { 7554, 3 }, { 7630, 2 }, { 7666, 2 }, { 7815, 1 }, { 7972, 1 }, { 7972, 2 }, { 7988, 2 }, { 8049, 8 }, { 8254, 2 }, { 8269, 2 }, { 8352, 1 }, { 8378, 2 }, { 8526, 2 },\n                { 8531, 2 }, { 8583, 2 }, { 8615, 2 }, { 8619, 3 }, { 8623, 2 }, { 8692, 1 }, { 8698, 2 }, { 8773, 2 }, { 8777, 3 }, { 8822, 2 }, { 8929, 2 }, { 8935, 2 }, { 9025, 2 }, { 9054, 2 }, { 9056, 1 }, { 9086, 2 }, { 9147, 3 }, { 9219, 2 }, { 9230, 3 }, { 9248, 2 }, { 9283, 2 }, { 9314, 2 }, { 9418, 1 }, { 9426, 2 }, { 9456, 1 },\n                { 9594, 2 }, { 9628, 2 }, { 9642, 2 }, { 9646, 2 }, { 9686, 1 }, { 9709, 2 }, { 9771, 3 }, { 9782, 2 }, { 9884, 2 }, { 9914, 5 }, { 10004, 4 }, { 10033, 6 }, { 10052, 2 }, { 10086, 2 }, { 10168, 2 }, { 10176, 1 }, { 10228, 2 }, { 10312, 2 }, { 10372, 2 }, { 10622, 2 }, { 10685, 2 }, { 10687, 1 }, { 10787, 2 }, { 11010, 2 },\n                { 11024, 2 }, { 11044, 2 }, { 11086, 2 }, { 11149, 1 }, { 11198, 2 }, { 11265, 2 }, { 11302, 2 }, { 11326, 2 }, { 11354, 2 }, { 11404, 1 }, { 11473, 2 }, { 11506, 2 }, { 11548, 4 }, { 11575, 2 }, { 11621, 4 }, { 11625, 3 }, { 11625, 1 }, { 11642, 4 }, { 11859, 5 }, { 11870, 2 }, { 11872, 3 }, { 11880, 7 }, { 11886, 3 },\n                { 11905, 6 }, { 11880, 3 }, { 11912, 6 }, { 11916, 4 }, { 11916, 3 }, { 11965, 4 }, { 12068, 13 }, { 12106, 2 }, { 12120, 2 }, { 12221, 2 }, { 12257, 2 }, { 12361, 2 }, { 12411, 2 }, { 12473, 3 }, { 12554, 2 }, { 12583, 2 }, { 12654, 2 }, { 12665, 2 }, { 12744, 1 }, { 12775, 2 }, { 12858, 2 }, { 12993, 2 }, { 13007, 3 },\n                { 13025, 4 }, { 13038, 2 }, { 13092, 4 }, { 13094, 5 }, { 13095, 1 }, { 13110, 2 }, { 13116, 1 }, { 13140, 2 }, { 13169, 1 }, { 13186, 2 }, { 13202, 2 }, { 13202, 1 }, { 13256, 2 }, { 13344, 2 }, { 13373, 2 }, { 13396, 3 }, { 13446, 2 }, { 13451, 3 }, { 13475, 2 }, { 13521, 1 }, { 13587, 2 }, { 13592, 2 }, { 13708, 3 },\n                { 13711, 1 }, { 13741, 1 }, { 13757, 1 }, { 13847, 2 }, { 13881, 3 }, { 13915, 1 }, { 14005, 2 }, { 14028, 2 }, { 14037, 2 }, { 14074, 2 }, { 14135, 2 }, { 14176, 2 }, { 14227, 2 }, { 14228, 2 }, { 14271, 3 }, { 14279, 3 }, { 14493, 2 }, { 14535, 3 }, { 14535, 1 }, { 14680, 2 }, { 14717, 2 }, { 14725, 1 }, { 14790, 2 },\n                { 14801, 1 }, { 14959, 2 }, { 15052, 2 }, { 15055, 1 }, { 15055, 1 }, { 15075, 2 }, { 15103, 8 }, { 15153, 16 }, { 15191, 2 }, { 15240, 2 }, { 15313, 2 }, { 15323, 2 }, { 15341, 1 }, { 15383, 2 }, { 15387, 2 }, { 15491, 2 }, { 15534, 2 }, { 15539, 2 }, { 15549, 2 }, { 15554, 1 }, { 15664, 1 }, { 15726, 2 }, { 15807, 2 },\n                { 15842, 2 }, { 15897, 2 }, { 15913, 3 }, { 15925, 2 }, { 15935, 2 }, { 16131, 1 }, { 16211, 3 }, { 16249, 2 }, { 16268, 2 }, { 16307, 2 }, { 16398, 2 }, { 16498, 2 }, { 16518, 1 }, { 16552, 1 }, { 16571, 2 }, { 16592, 2 }, { 16601, 3 }, { 16638, 2 }, { 16698, 2 }, { 16712, 1 }, { 16767, 2 }, { 16789, 2 }, { 16992, 2 },\n                { 17015, 2 }, { 17035, 2 }, { 17074, 3 }, { 17086, 3 }, { 17086, 1 }, { 17092, 1 }, { 17110, 4 }, { 17116, 3 }, { 17236, 2 }, { 17291, 2 }, { 17291, 2 }, { 17340, 2 }, { 17342, 1 }, { 17360, 3 }, { 17436, 3 }, { 17457, 2 }, { 17508, 1 }, { 17556, 2 }, { 17601, 2 }, { 17639, 2 }, { 17671, 2 }, { 17743, 2 }, { 17857, 2 },\n                { 17915, 2 }, { 17992, 2 }, { 18077, 1 }, { 18088, 2 }, { 18158, 1 }, { 18239, 16 }, { 18242, 2 }, { 18252, 3 }, { 18299, 1 }, { 18405, 2 }, { 18433, 2 }, { 18444, 2 }, { 18490, 2 }, { 18497, 2 }, { 18516, 2 }, { 18540, 2 }, { 18598, 2 }, { 18649, 2 }, { 18658, 2 }, { 18683, 2 }, { 18728, 2 }, { 18767, 1 }, { 18821, 2 },\n                { 18868, 2 }, { 18876, 2 }, { 18914, 14 }, { 19212, 1 }, { 19215, 1 }, { 19293, 2 }, { 19303, 2 }, { 19336, 2 }, { 19376, 2 }, { 19419, 2 }, { 19558, 2 }, { 19559, 1 }, { 19609, 2 }, { 19688, 2 }, { 19724, 2 }, { 19820, 1 }, { 19851, 2 }, { 19881, 2 }, { 19966, 2 }, { 19983, 3 }, { 19988, 4 }, { 20047, 1 }, { 20062, 2 },\n                { 20091, 1 }, { 20152, 1 }, { 20183, 1 }, { 20208, 2 }, { 20346, 2 }, { 20386, 1 }, { 20459, 2 }, { 20505, 2 }, { 20520, 1 }, { 20560, 3 }, { 20566, 3 }, { 20566, 1 }, { 20610, 2 }, { 20652, 2 }, { 20694, 2 }, { 20740, 2 }, { 20756, 2 }, { 20825, 3 }, { 20895, 2 }, { 20959, 1 }, { 20995, 2 }, { 21017, 3 }, { 21039, 2 },\n                { 21086, 1 }, { 21109, 3 }, { 21139, 3 }, { 21206, 2 }, { 21230, 2 }, { 21251, 3 }, { 21352, 2 }, { 21353, 2 }, { 21370, 3 }, { 21389, 1 }, { 21445, 3 }, { 21475, 2 }, { 21528, 2 }, { 21559, 3 }, { 21604, 2 }, { 21606, 1 }, { 21815, 2 }, { 21858, 3 }, { 21860, 3 }, { 22015, 2 }, { 22065, 2 }, { 22098, 5 }, { 22105, 2 },\n                { 22158, 3 }, { 22197, 2 }, { 22254, 1 }, { 22353, 2 }, { 22404, 4 }, { 22422, 2 }, { 22569, 2 }, { 22634, 2 }, { 22639, 2 }, { 22861, 2 }, { 22868, 2 }, { 22876, 1 }, { 22902, 2 }, { 22925, 2 }, { 23080, 2 }, { 23085, 3 }, { 23089, 5 }, { 23329, 1 }, { 23349, 2 }, { 23559, 5 }, { 23567, 3 }, { 23574, 2 }, { 23584, 3 },\n                { 23615, 3 }, { 23633, 2 }, { 23674, 2 }, { 23678, 1 }, { 23853, 2 }, { 23875, 2 }, { 24010, 4 }, { 24076, 2 }, { 24128, 6 }, { 24248, 2 }, { 24253, 2 }, { 24259, 1 }, { 24319, 2 }, { 24319, 1 }, { 24502, 3 }, { 24666, 2 }, { 24781, 3 }, { 24792, 2 }, { 24909, 2 }, { 24993, 2 }, { 25039, 1 }, { 25090, 3 }, { 25137, 1 },\n                { 25138, 3 }, { 25140, 3 }, { 25155, 5 }, { 25411, 2 }, { 25460, 2 }, { 25564, 3 }, { 25586, 3 }, { 25630, 2 }, { 25765, 2 }, { 25789, 3 }, { 25803, 2 }, { 25851, 2 }, { 25872, 2 }, { 25887, 2 }, { 25981, 1 }, { 26016, 2 }, { 26019, 1 }, { 26029, 1 }, { 26104, 7 }, { 26144, 2 }, { 26275, 1 }, { 26295, 2 }, { 26298, 1 },\n                { 26322, 2 }, { 26380, 2 }, { 26408, 4 }, { 26446, 1 }, { 26553, 1 }, { 26576, 1 }, { 26635, 1 }, { 26668, 2 }, { 26675, 2 }, { 26698, 4 }, { 26748, 9 }, { 26788, 2 }, { 26932, 2 }, { 26962, 2 }, { 27042, 2 }, { 27060, 2 }, { 27163, 3 }, { 27202, 2 }, { 27290, 2 }, { 27337, 3 }, { 27376, 2 }, { 27439, 2 }, { 27458, 4 },\n                { 27515, 2 }, { 27518, 1 }, { 27541, 2 }, { 27585, 3 }, { 27633, 2 }, { 27695, 2 }, { 27702, 2 }, { 27861, 2 }, { 27924, 1 }, { 28025, 14 }, { 28058, 2 }, { 28143, 2 }, { 28215, 2 }, { 28240, 2 }, { 28241, 2 }, { 28285, 2 }, { 28324, 3 }, { 28378, 2 }, { 28514, 2 }, { 28529, 2 }, { 28538, 2 }, { 28565, 3 }, { 28697, 2 },\n                { 28735, 2 }, { 28769, 2 }, { 28770, 4 }, { 28788, 4 }, { 28807, 3 }, { 28807, 4 }, { 28829, 1 }, { 28853, 2 }, { 28856, 7 }, { 28864, 2 }, { 28865, 3 }, { 28915, 2 }, { 28928, 2 }, { 28964, 2 }, { 28988, 1 }, { 29031, 2 }, { 29095, 2 }, { 29189, 2 }, { 29205, 1 }, { 29230, 1 }, { 29332, 2 }, { 29339, 2 }, { 29349, 5 },\n                { 29449, 2 }, { 29471, 2 }, { 29578, 2 }, { 29859, 2 }, { 29878, 2 }, { 29947, 10 }, { 30083, 2 }, { 30121, 2 }, { 30128, 2 }, { 30155, 4 }, { 30157, 1 }, { 30272, 2 }, { 30281, 2 }, { 30286, 2 }, { 30305, 2 }, { 30408, 2 }, { 30444, 22 }, { 30612, 2 }, { 30628, 2 }, { 30747, 2 }, { 30783, 2 }, { 30808, 5 }, { 30868, 3 },\n                { 30875, 2 }, { 30997, 2 }, { 31000, 2 }, { 31022, 3 }, { 31111, 1 }, { 31144, 2 }, { 31146, 3 }, { 31187, 2 }, { 31324, 2 }, { 31343, 2 }, { 31416, 2 }, { 31485, 2 }, { 31539, 2 }, { 31638, 2 }, { 31648, 2 }, { 31750, 2 }, { 31754, 2 }, { 31785, 10 }, { 31786, 5 }, { 31800, 2 }, { 31801, 4 }, { 31807, 7 }, { 31807, 3 },\n                { 31807, 10 }, { 31808, 3 }, { 31808, 4 }, { 31818, 6 }, { 31825, 7 }, { 31838, 2 }, { 31911, 1 }, { 31974, 2 }, { 32010, 3 }, { 32031, 2 }, { 32040, 2 }, { 32063, 1 }, { 32078, 2 }, { 32156, 2 }, { 32198, 31 }, { 32257, 2 }, { 32257, 2 }, { 32265, 2 }, { 32330, 2 }, { 32369, 8 }, { 32404, 3 }, { 32425, 2 }, { 32432, 2 },\n                { 32505, 2 }, { 32531, 2 }, { 32536, 2 }, { 32549, 2 }, { 32582, 3 }, { 32590, 4 }, { 32624, 2 }, { 32644, 2 }, { 32692, 2 }, { 32695, 4 }, { 32699, 3 }, { 32726, 4 }, { 32784, 2 }, { 32832, 2 }, { 32883, 6 }, { 32965, 4 }, { 33044, 2 }, { 33104, 2 }, { 33184, 2 }, { 33264, 1 }, { 33292, 2 }, { 33312, 1 }, { 33468, 2 },\n                { 33471, 1 }, { 33565, 2 }, { 33627, 2 }, { 33659, 2 }, { 33709, 2 }, { 33766, 5 }, { 33836, 2 }, { 33875, 2 }, { 33954, 2 }, { 33959, 2 }, { 34050, 2 }, { 34090, 2 }, { 34168, 2 }, { 34233, 2 }, { 34461, 2 }, { 34462, 1 }, { 34463, 2 }, { 34472, 4 }, { 34500, 2 }, { 34520, 2 }, { 34544, 2 }, { 34614, 2 }, { 34662, 1 },\n                { 34676, 2 }, { 34729, 4 }, { 34803, 2 }, { 34845, 2 }, { 34913, 2 }, { 34963, 6 }, { 35019, 2 }, { 35022, 2 }, { 35070, 2 }, { 35120, 2 }, { 35132, 2 }, { 35144, 2 }, { 35205, 2 }, { 35230, 3 }, { 35244, 2 }, { 35271, 4 }, { 35276, 2 }, { 35282, 2 }, { 35324, 3 }, { 35366, 3 }, { 35659, 2 }, { 35680, 2 }, { 35744, 2 },\n                { 35758, 3 }, { 35796, 2 }, { 35830, 2 }, { 35841, 7 }, { 35843, 2 }, { 35856, 2 }, { 35914, 4 }, { 35929, 13 }, { 35993, 2 }, { 35997, 1 }, { 36046, 4 }, { 36046, 1 }, { 36051, 1 }, { 36111, 2 }, { 36208, 1 }, { 36208, 1 }, { 36306, 2 }, { 36325, 2 }, { 36386, 2 }, { 36405, 2 }, { 36443, 1 }, { 36455, 1 }, { 36538, 2 },\n                { 36562, 2 }, { 36566, 2 }, { 36628, 2 }, { 36693, 2 }, { 36713, 2 }, { 36730, 2 }, { 36747, 2 }, { 36786, 2 }, { 36810, 1 }, { 36848, 2 }, { 36914, 1 }, { 36920, 2 }, { 36952, 2 }, { 37071, 2 }, { 37086, 1 }, { 37094, 3 }, { 37158, 3 }, { 37231, 2 }, { 37241, 2 }, { 37285, 2 }, { 37349, 2 }, { 37404, 2 }, { 37410, 1 },\n                { 37433, 4 }, { 37615, 2 }, { 37659, 2 }, { 37742, 2 }, { 37773, 2 }, { 37867, 1 }, { 37890, 2 }, { 37960, 2 }, { 38042, 3 }, { 38241, 2 }, { 38400, 2 }, { 38461, 1 }, { 38551, 2 }, { 38611, 1 }, { 38657, 2 }, { 38729, 2 }, { 38748, 2 }, { 38815, 2 }, { 38852, 2 }, { 38890, 1 }, { 38954, 2 }, { 39119, 2 }, { 39162, 2 },\n                { 39175, 3 }, { 39176, 2 }, { 39231, 2 }, { 39261, 2 }, { 39467, 2 }, { 39500, 2 }, { 39507, 2 }, { 39566, 2 }, { 39608, 2 }, { 39686, 6 }, { 39730, 2 }, { 39842, 1 }, { 39853, 1 }, { 39905, 2 }, { 39931, 2 }, { 39989, 2 }, { 40030, 2 }, { 40227, 2 }, { 40268, 2 }, { 40372, 2 }, { 40415, 1 }, { 40488, 3 }, { 40536, 2 },\n                { 40676, 3 }, { 40677, 2 }, { 40755, 2 }, { 40842, 2 }, { 40849, 1 }, { 40870, 3 }, { 40873, 3 }, { 40972, 2 }, { 41033, 2 }, { 41190, 2 }, { 41273, 5 }, { 41273, 1 }, { 41293, 2 }, { 41367, 32 }, { 41376, 2 }, { 41420, 2 }, { 41473, 2 }, { 41473, 2 }, { 41493, 4 }, { 41521, 2 }, { 41533, 2 }, { 41554, 2 }, { 41568, 2 },\n                { 41583, 3 }, { 41728, 2 }, { 41786, 2 }, { 41836, 1 }, { 41875, 2 }, { 41933, 2 }, { 42044, 2 }, { 42075, 2 }, { 42076, 2 }, { 42133, 2 }, { 42259, 29 }, { 42269, 3 }, { 42294, 2 }, { 42420, 2 }, { 42524, 2 }, { 42524, 1 }, { 42546, 1 }, { 42631, 2 }, { 42693, 2 }, { 42740, 2 }, { 42744, 4 }, { 42755, 1 }, { 42870, 2 },\n                { 42894, 2 }, { 42939, 2 }, { 42973, 2 }, { 43016, 2 }, { 43070, 2 }, { 43105, 2 }, { 43115, 2 }, { 43375, 3 }, { 43387, 1 }, { 43424, 3 }, { 43448, 2 }, { 43480, 2 }, { 43498, 2 }, { 43651, 2 }, { 43727, 2 }, { 43879, 2 }, { 43910, 1 }, { 43977, 2 }, { 44003, 2 }, { 44080, 2 }, { 44082, 1 }, { 44136, 2 }, { 44169, 29 },\n                { 44186, 2 }, { 44339, 2 }, { 44350, 1 }, { 44356, 1 }, { 44430, 2 }, { 44440, 1 }, { 44530, 1 }, { 44538, 2 }, { 44572, 2 }, { 44585, 2 }, { 44709, 2 }, { 44748, 2 }, { 44748, 2 }, { 44769, 2 }, { 44813, 2 }, { 44890, 2 }, { 45015, 2 }, { 45046, 4 }, { 45052, 2 }, { 45062, 2 }, { 45094, 6 }, { 45184, 2 }, { 45191, 2 },\n                { 45201, 3 }, { 45216, 3 }, { 45227, 2 }, { 45269, 1 }, { 45294, 2 }, { 45314, 2 }, { 45345, 8 }, { 45352, 2 }, { 45365, 3 }, { 45378, 1 }, { 45392, 4 }, { 45405, 3 }, { 45410, 2 }, { 45448, 14 }, { 45450, 2 }, { 45457, 2 }, { 45466, 3 }, { 45481, 4 }, { 45486, 7 }, { 45533, 5 }, { 45576, 2 }, { 45649, 2 }, { 45917, 2 },\n                { 45919, 6 }, { 45919, 1 }, { 45930, 15 }, { 45930, 2 }, { 46001, 5 }, { 46036, 2 }, { 46054, 2 }, { 46075, 2 }, { 46153, 2 }, { 46155, 2 }, { 46228, 2 }, { 46234, 2 }, { 46273, 2 }, { 46387, 2 }, { 46398, 2 }, { 46517, 2 }, { 46559, 2 }, { 46565, 1 }, { 46598, 2 }, { 46686, 2 }, { 46744, 2 }, { 46816, 3 }, { 46835, 2 },\n                { 46921, 2 }, { 46938, 2 }, { 46991, 2 }, { 47038, 2 }, { 47098, 3 }, { 47107, 2 }, { 47201, 3 }, { 47327, 1 }, { 47327, 1 }, { 47338, 2 }, { 47395, 1 }, { 47499, 2 }, { 47504, 2 }, { 47515, 1 }, { 47516, 1 }, { 47600, 1 }, { 47604, 1 }, { 47707, 1 }, { 47728, 1 }, { 47748, 2 }, { 47763, 2 }, { 47807, 4 }, { 47814, 2 },\n                { 47822, 2 }, { 47834, 2 }, { 47843, 3 }, { 47886, 2 }, { 47893, 2 }, { 48066, 2 }, { 48126, 2 }, { 48133, 1 }, { 48166, 2 }, { 48299, 1 }, { 48455, 2 }, { 48468, 2 }, { 48568, 2 }, { 48606, 2 }, { 48642, 2 }, { 48698, 2 }, { 48714, 2 }, { 48754, 2 }, { 48765, 3 }, { 48773, 5 }, { 48819, 2 }, { 48833, 2 }, { 48904, 2 },\n                { 49000, 1 }, { 49113, 12 }, { 49140, 2 }, { 49276, 2 }, { 49353, 2 }, { 49411, 3 }, { 49418, 2 }, { 49540, 2 }, { 49544, 2 }, { 49584, 2 }, { 49602, 2 }, { 49784, 5 }, { 49822, 4 }, { 49822, 5 }, { 49828, 2 }, { 49866, 2 }, { 49922, 3 }, { 49959, 2 }, { 50045, 2 }, { 50134, 3 }, { 50140, 2 }, { 50237, 2 }, { 50247, 2 },\n                { 50266, 13 }, { 50290, 2 }, { 50312, 4 }, { 50314, 1 }, { 50527, 2 }, { 50605, 1 }, { 50730, 2 }, { 50751, 2 }, { 50770, 2 }, { 50858, 2 }, { 50859, 2 }, { 50909, 2 }, { 50948, 3 }, { 51043, 2 }, { 51048, 2 }, { 51089, 2 }, { 51090, 2 }, { 51141, 2 }, { 51163, 2 }, { 51250, 2 }, { 51347, 2 }, { 51475, 2 }, { 51536, 2 },\n                { 51544, 2 }, { 51595, 2 }, { 51602, 19 }, { 51643, 5 }, { 51702, 2 }, { 51702, 10 }, { 51764, 2 }, { 51793, 5 }, { 51812, 2 }, { 51839, 1 }, { 51938, 3 }, { 51941, 1 }, { 51967, 4 }, { 52049, 3 }, { 52074, 3 }, { 52098, 2 }, { 52118, 2 }, { 52119, 3 }, { 52227, 11 }, { 52246, 3 }, { 52282, 2 }, { 52451, 2 }, { 52583, 2 },\n                { 52601, 1 }, { 52605, 2 }, { 52615, 2 }, { 52668, 2 }, { 52824, 2 }, { 53076, 1 }, { 53120, 1 }, { 53179, 2 }, { 53189, 2 }, { 53193, 1 }, { 53195, 2 }, { 53246, 2 }, { 53249, 2 }, { 53268, 1 }, { 53295, 2 }, { 53312, 2 }, { 53410, 2 }, { 53451, 2 }, { 53570, 2 }, { 53593, 2 }, { 53635, 2 }, { 53657, 2 }, { 53682, 3 },\n                { 53728, 5 }, { 53733, 2 }, { 53753, 2 }, { 53787, 4 }, { 53807, 1 }, { 54008, 2 }, { 54059, 2 }, { 54060, 1 }, { 54080, 2 }, { 54090, 1 }, { 54138, 2 }, { 54149, 2 }, { 54168, 1 }, { 54171, 2 }, { 54216, 22 }, { 54233, 6 }, { 54434, 2 }, { 54534, 2 }, { 54562, 2 }, { 54763, 2 }, { 54791, 2 }, { 54816, 2 }, { 54909, 2 },\n                { 54916, 3 }, { 54963, 2 }, { 54985, 2 }, { 54991, 3 }, { 55016, 3 }, { 55025, 3 }, { 55032, 2 }, { 55099, 2 }, { 55260, 2 }, { 55261, 2 }, { 55270, 3 }, { 55384, 2 }, { 55455, 2 }, { 55456, 2 }, { 55504, 3 }, { 55510, 2 }, { 55558, 2 }, { 55568, 2 }, { 55585, 2 }, { 55677, 2 }, { 55703, 2 }, { 55749, 2 }, { 55779, 2 },\n                { 55789, 3 }, { 55792, 2 }, { 55830, 4 }, { 55835, 2 }, { 55879, 2 }, { 56076, 2 }, { 56118, 2 }, { 56314, 2 }, { 56392, 1 }, { 56411, 2 }, { 56459, 2 }, { 56553, 34 }, { 56575, 2 }, { 56733, 2 }, { 56762, 2 }, { 56793, 3 }, { 56877, 3 }, { 56927, 2 }, { 56981, 2 }, { 57014, 1 }, { 57149, 2 }, { 57162, 2 }, { 57186, 2 },\n                { 57254, 2 }, { 57267, 1 }, { 57324, 2 }, { 57327, 2 }, { 57365, 4 }, { 57371, 2 }, { 57445, 2 }, { 57477, 2 }, { 57497, 2 }, { 57536, 2 }, { 57609, 2 }, { 57626, 2 }, { 57666, 2 }, { 57694, 2 }, { 57694, 2 }, { 57749, 2 }, { 57781, 7 }, { 57878, 2 }, { 57953, 2 }, { 58051, 2 }, { 58088, 2 }, { 58097, 2 }, { 58142, 3 },\n                { 58142, 1 }, { 58197, 1 }, { 58221, 2 }, { 58222, 2 }, { 58244, 2 }, { 58290, 1 }, { 58296, 1 }, { 58325, 2 }, { 58378, 1 }, { 58389, 3 }, { 58430, 2 }, { 58454, 2 }, { 58551, 29 }, { 58563, 6 }, { 58681, 2 }, { 58751, 8 }, { 58752, 43 }, { 58790, 5 }, { 58846, 2 }, { 58879, 6 }, { 58953, 2 }, { 58998, 2 }, { 59010, 1 },\n                { 59038, 5 }, { 59135, 2 }, { 59166, 2 }, { 59180, 2 }, { 59222, 2 }, { 59227, 2 }, { 59307, 2 }, { 59398, 3 }, { 59411, 2 }, { 59436, 3 }, { 59464, 2 }, { 59569, 2 }, { 59587, 2 }, { 59624, 3 }, { 59786, 2 }, { 59834, 2 }, { 59841, 2 }, { 59841, 1 }, { 59984, 2 }, { 59985, 2 }, { 60003, 3 }, { 60045, 2 }, { 60097, 2 },\n                { 60148, 2 }, { 60172, 2 }, { 60203, 5 }, { 60565, 2 }, { 60625, 2 }, { 60743, 2 }, { 60781, 2 }, { 60892, 2 }, { 60977, 2 }, { 60979, 2 }, { 61021, 5 }, { 61021, 4 }, { 61026, 2 }, { 61139, 2 }, { 61165, 3 }, { 61204, 2 }, { 61207, 1 }, { 61248, 3 }, { 61257, 2 }, { 61264, 6 }, { 61272, 3 }, { 61410, 2 }, { 61410, 3 },\n                { 61416, 2 }, { 61423, 1 }, { 61503, 2 }, { 61503, 2 }, { 61533, 2 }, { 61567, 2 }, { 61575, 2 }, { 61835, 1 }, { 61842, 1 }, { 61924, 2 }, { 61951, 6 }, { 61975, 2 }, { 61986, 3 }, { 62024, 1 }, { 62110, 2 }, { 62135, 2 }, { 62192, 2 }, { 62208, 2 }, { 62399, 2 }, { 62400, 1 }, { 62414, 2 }, { 62423, 3 }, { 62456, 3 },\n                { 62459, 3 }, { 62478, 3 }, { 62484, 2 }, { 62510, 6 }, { 62511, 3 }, { 62565, 3 }, { 62610, 2 }, { 62875, 4 }, { 62896, 5 }, { 62898, 2 }, { 62904, 2 }, { 62938, 3 }, { 62943, 2 }, { 62977, 2 }, { 62989, 3 }, { 62998, 5 }, { 63069, 1 }, { 63093, 5 }, { 63107, 2 }, { 63113, 1 }, { 63231, 4 }, { 63253, 2 }, { 63286, 4 },\n                { 63289, 2 }, { 63334, 1 }, { 63334, 4 }, { 63413, 2 }, { 63425, 2 }, { 63512, 10 }, { 63537, 1 }, { 63694, 1 }, { 63721, 4 }, { 63749, 2 }, { 63783, 17 }, { 63791, 3 }, { 63792, 2 }, { 63882, 25 }, { 63896, 1 }, { 63936, 2 }, { 63969, 3 }, { 63986, 2 }, { 63988, 2 }, { 64009, 10 }, { 64018, 2 }, { 64032, 6 }, { 64125, 2 },\n                { 64195, 1 }, { 64221, 7 }, { 64390, 2 }, { 64459, 2 }, { 64568, 2 }, { 64784, 1 }, { 64789, 2 }, { 64829, 2 }, { 64848, 1 }, { 64914, 2 }, { 64928, 1 }, { 64939, 2 }, { 65026, 2 }, { 65057, 2 }, { 65070, 2 }, { 65193, 4 }, { 65235, 3 }, { 65242, 2 }, { 65281, 2 }, { 65320, 2 }, { 65365, 1 }, { 65414, 2 }, { 65445, 2 },\n                { 65581, 2 }, { 65624, 1 }, { 65719, 2 }, { 65766, 2 }, { 65927, 2 }, { 66004, 1 }, { 66031, 2 }, { 66085, 1 }, { 66085, 2 }, { 66133, 2 }, { 66134, 2 }, { 66188, 1 }, { 66240, 2 }, { 66249, 2 }, { 66250, 2 }, { 66295, 2 }, { 66342, 1 }, { 66352, 3 }, { 66388, 3 }, { 66432, 2 }, { 66437, 47 }, { 66497, 2 }, { 66517, 2 },\n                { 66526, 2 }, { 66546, 9 }, { 66605, 2 }, { 66753, 2 }, { 66792, 2 }, { 66796, 2 }, { 66828, 2 }, { 66899, 3 }, { 66970, 6 }, { 66981, 2 }, { 66983, 1 }, { 67009, 2 }, { 67017, 4 }, { 67115, 2 }, { 67117, 1 }, { 67130, 6 }, { 67132, 7 }, { 67162, 2 }, { 67179, 6 }, { 67236, 2 }, { 67263, 3 }, { 67274, 2 }, { 67274, 2 },\n                { 67349, 3 }, { 67486, 2 }, { 67503, 3 }, { 67517, 1 }, { 67559, 1 }, { 67660, 2 }, { 67727, 2 }, { 67901, 2 }, { 67943, 4 }, { 67950, 2 }, { 67965, 3 }, { 68029, 2 }, { 68048, 2 }, { 68169, 2 }, { 68172, 1 }, { 68258, 2 }, { 68288, 1 }, { 68359, 2 }, { 68441, 2 }, { 68484, 2 }, { 68488, 2 }, { 68525, 2 }, { 68535, 2 },\n                { 68575, 7 }, { 68575, 5 }, { 68583, 2 }, { 68588, 4 }, { 68593, 1 }, { 68597, 2 }, { 68636, 2 }, { 68636, 2 }, { 68667, 2 }, { 68785, 1 }, { 68914, 4 }, { 68915, 5 }, { 68940, 3 }, { 69010, 2 }, { 69063, 2 }, { 69076, 2 }, { 69235, 2 }, { 69270, 2 }, { 69298, 1 }, { 69350, 5 }, { 69432, 2 }, { 69514, 2 }, { 69562, 3 },\n                { 69562, 4 }, { 69638, 1 }, { 69656, 2 }, { 69709, 2 }, { 69775, 2 }, { 69788, 2 }, { 70193, 2 }, { 70233, 2 }, { 70252, 2 }, { 70259, 2 }, { 70293, 3 }, { 70405, 3 }, { 70462, 2 }, { 70515, 3 }, { 70518, 2 }, { 70535, 6 }, { 70547, 6 }, { 70577, 6 }, { 70631, 17 }, { 70667, 2 }, { 70680, 1 }, { 70694, 1 }, { 70898, 2 },\n                { 70916, 1 }, { 70936, 3 }, { 71033, 2 }, { 71126, 2 }, { 71158, 2 }, { 71162, 2 }, { 71421, 1 }, { 71441, 2 }, { 71557, 2 }, { 71789, 1 }, { 71816, 2 }, { 71850, 1 }, { 71869, 1 }, { 71961, 2 }, { 71973, 4 }, { 72064, 2 }, { 72110, 2 }, { 72117, 3 }, { 72164, 2 }, { 72266, 2 }, { 72325, 2 }, { 72326, 1 }, { 72420, 2 },\n                { 72693, 2 }, { 72705, 1 }, { 72730, 2 }, { 72793, 2 }, { 72795, 1 }, { 72939, 1 }, { 72945, 3 }, { 72945, 2 }, { 73120, 1 }, { 73121, 5 }, { 73122, 4 }, { 73126, 1 }, { 73126, 1 }, { 73196, 3 }, { 73219, 2 }, { 73241, 6 }, { 73272, 3 }, { 73354, 1 }, { 73368, 2 }, { 73467, 1 }, { 73517, 2 }, { 73554, 2 }, { 73678, 2 },\n                { 73838, 1 }, { 73881, 2 }, { 73958, 2 }, { 73985, 15 }, { 74092, 2 }, { 74205, 2 }, { 74245, 2 }, { 74277, 2 }, { 74286, 2 }, { 74353, 2 }, { 74403, 2 }, { 74428, 1 }, { 74468, 2 }, { 74481, 3 }, { 74511, 2 }, { 74537, 2 }, { 74596, 2 }, { 74750, 2 }, { 74754, 2 }, { 74861, 2 }, { 74933, 4 }, { 74970, 1 }, { 75003, 3 },\n                { 75077, 1 }, { 75159, 2 }, { 75170, 2 }, { 75234, 2 }, { 75300, 3 }, { 75337, 2 }, { 75345, 2 }, { 75419, 1 }, { 75429, 2 }, { 75477, 1 }, { 75513, 2 }, { 75536, 2 }, { 75536, 2 }, { 75539, 1 }, { 75551, 2 }, { 75561, 2 }, { 75565, 2 }, { 75590, 2 }, { 75623, 5 }, { 75773, 6 }, { 75777, 6 }, { 75785, 2 }, { 75791, 2 },\n                { 75804, 2 }, { 75862, 2 }, { 75924, 3 }, { 75927, 2 }, { 75996, 11 }, { 76000, 1 }, { 76006, 2 }, { 76020, 3 }, { 76110, 2 }, { 76126, 3 }, { 76131, 2 }, { 76136, 2 }, { 76144, 2 }, { 76203, 2 }, { 76229, 3 }, { 76244, 15 }, { 76246, 2 }, { 76300, 1 }, { 76403, 3 }, { 76545, 2 }, { 76569, 2 }, { 76813, 2 }, { 76821, 2 },\n                { 76837, 2 }, { 76863, 2 }, { 77027, 2 }, { 77037, 2 }, { 77074, 3 }, { 77170, 2 }, { 77191, 2 }, { 77220, 2 }, { 77230, 2 }, { 77261, 2 }, { 77277, 2 }, { 77309, 2 }, { 77314, 2 }, { 77412, 2 }, { 77419, 2 }, { 77457, 2 }, { 77633, 3 }, { 77714, 2 }, { 77855, 2 }, { 77857, 1 }, { 77876, 2 }, { 77895, 2 }, { 77916, 5 },\n                { 77947, 2 }, { 77948, 1 }, { 77966, 1 }, { 77996, 2 }, { 78025, 1 }, { 78064, 2 }, { 78100, 2 }, { 78113, 1 }, { 78114, 3 }, { 78167, 2 }, { 78175, 2 }, { 78260, 2 }, { 78261, 1 }, { 78265, 2 }, { 78286, 1 }, { 78300, 2 }, { 78327, 3 }, { 78363, 1 }, { 78384, 2 }, { 78459, 2 }, { 78516, 2 }, { 78612, 2 }, { 78643, 2 },\n                { 78655, 2 }, { 78698, 1 }, { 78720, 3 }, { 78789, 3 }, { 78838, 5 }, { 78893, 1 }, { 78954, 7 }, { 79007, 2 }, { 79132, 3 }, { 79193, 2 }, { 79193, 2 }, { 79226, 2 }, { 79411, 2 }, { 79422, 1 }, { 79502, 2 }, { 79593, 2 }, { 79622, 2 }, { 79657, 3 }, { 79771, 2 }, { 79866, 2 }, { 79909, 2 }, { 80005, 2 }, { 80032, 2 },\n                { 80060, 1 }, { 80132, 2 }, { 80149, 3 }, { 80251, 2 }, { 80363, 2 }, { 80379, 1 }, { 80464, 2 }, { 80498, 2 }, { 80553, 2 }, { 80556, 3 }, { 80559, 1 }, { 80571, 2 }, { 80652, 1 }, { 80703, 2 }, { 80754, 2 }, { 80754, 2 }, { 80860, 2 }, { 81055, 2 }, { 81087, 4 }, { 81210, 2 }, { 81211, 1 }, { 81216, 1 }, { 81223, 1 },\n                { 81231, 1 }, { 81288, 2 }, { 81317, 2 }, { 81327, 3 }, { 81332, 2 }, { 81376, 2 }, { 81469, 2 }, { 81579, 2 }, { 81617, 1 }, { 81630, 2 }, { 81666, 2 }, { 81800, 2 }, { 81832, 2 }, { 81848, 2 }, { 81869, 2 }, { 81941, 3 }, { 82177, 3 }, { 82179, 2 }, { 82180, 2 }, { 82182, 4 }, { 82185, 2 }, { 82195, 2 }, { 82238, 4 },\n                { 82265, 3 }, { 82295, 10 }, { 82299, 9 }, { 82367, 3 }, { 82379, 3 }, { 82380, 1 }, { 82505, 2 }, { 82568, 2 }, { 82620, 1 }, { 82637, 5 }, { 82821, 2 }, { 82841, 2 }, { 82945, 1 }, { 83020, 12 }, { 83072, 2 }, { 83181, 2 }, { 83240, 2 }, { 83253, 3 }, { 83261, 2 }, { 83288, 2 }, { 83291, 4 }, { 83295, 3 }, { 83365, 2 },\n                { 83368, 2 }, { 83408, 2 }, { 83458, 2 }, { 83470, 2 }, { 83471, 1 }, { 83637, 3 }, { 83693, 2 }, { 83703, 2 }, { 83732, 2 }, { 83745, 1 }, { 83800, 4 }, { 83801, 3 }, { 83856, 3 }, { 83863, 5 }, { 83867, 2 }, { 83868, 3 }, { 83898, 7 }, { 83900, 4 }, { 83901, 5 }, { 83989, 2 }, { 84049, 35 }, { 84086, 2 }, { 84089, 2 },\n                { 84115, 3 }, { 84130, 3 }, { 84132, 2 }, { 84143, 3 }, { 84173, 2 }, { 84185, 5 }, { 84297, 2 }, { 84390, 2 }, { 84497, 4 }, { 84657, 2 }, { 84657, 2 }, { 84724, 2 }, { 84775, 2 }, { 84870, 2 }, { 84892, 2 }, { 84910, 3 }, { 84935, 3 }, { 85002, 2 }, { 85051, 2 }, { 85052, 2 }, { 85135, 25 }, { 85135, 2 }, { 85144, 2 },\n                { 85165, 3 }, { 85205, 2 }, { 85232, 2 }, { 85281, 5 }, { 85423, 6 }, { 85539, 2 }, { 85582, 4 }, { 85609, 2 }, { 85701, 36 }, { 85705, 2 }, { 85824, 2 }, { 85824, 2 }, { 85858, 30 }, { 85858, 28 }, { 85904, 35 }, { 85910, 2 }, { 85913, 2 }, { 85926, 3 }, { 85942, 4 }, { 85969, 4 }, { 85996, 1 }, { 86013, 3 }, { 86034, 13 },\n                { 86068, 8 }, { 86069, 8 }, { 86089, 8 }, { 86193, 13 }, { 86217, 7 }, { 86219, 2 }, { 86250, 2 }, { 86304, 16 }, { 86317, 2 }, { 86322, 4 }, { 86325, 2 }, { 86333, 2 }, { 86394, 2 }, { 86433, 2 }, { 86469, 3 }, { 86512, 4 }, { 86537, 2 }, { 86627, 2 }, { 86658, 2 }, { 86810, 2 }, { 86813, 2 }, { 86884, 2 }, { 86947, 2 },\n                { 87003, 2 }, { 87010, 5 }, { 87019, 2 }, { 87027, 2 }, { 87105, 2 }, { 87107, 2 }, { 87183, 2 }, { 87273, 2 }, { 87358, 3 }, { 87388, 3 }, { 87503, 4 }, { 87639, 2 }, { 87649, 4 }, { 87722, 2 }, { 87829, 2 }, { 87829, 1 }, { 87863, 2 }, { 87894, 2 }, { 87988, 32 }, { 88035, 27 }, { 88059, 3 }, { 88094, 5 }, { 88111, 21 },\n                { 88129, 2 }, { 88175, 5 }, { 88256, 2 }, { 88329, 2 }, { 88415, 3 }, { 88482, 2 }, { 88502, 1 }, { 88529, 2 }, { 88551, 3 }, { 88552, 1 }, { 88713, 2 }, { 88797, 2 }, { 88844, 27 }, { 88925, 5 }, { 88935, 2 }, { 88944, 1 }, { 89073, 2 }, { 89095, 3 }, { 89283, 2 }, { 89294, 3 }, { 89299, 2 }, { 89324, 2 }, { 89368, 2 },\n                { 89387, 2 }, { 89464, 2 }, { 89607, 2 }, { 89737, 2 }, { 89791, 2 }, { 89794, 3 }, { 89840, 2 }, { 89849, 3 }, { 89859, 2 }, { 89905, 2 }, { 89952, 38 }, { 90030, 7 }, { 90030, 6 }, { 90031, 1 }, { 90072, 2 }, { 90090, 2 }, { 90146, 3 }, { 90202, 23 }, { 90302, 3 }, { 90328, 14 }, { 90335, 14 }, { 90338, 8 }, { 90380, 2 },\n                { 90434, 1 }, { 90482, 2 }, { 90527, 9 }, { 90537, 3 }, { 90545, 2 }, { 90639, 5 }, { 90642, 2 }, { 90709, 2 }, { 90775, 1 }, { 90806, 2 }, { 90845, 19 }, { 90872, 4 }, { 90884, 2 }, { 90910, 2 }, { 90994, 5 }, { 91046, 8 }, { 91059, 8 }, { 91096, 39 }, { 91147, 2 }, { 91168, 1 }, { 91493, 2 }, { 91513, 3 }, { 91618, 3 },\n                { 91653, 2 }, { 91817, 2 }, { 91831, 3 }, { 91833, 3 }, { 91885, 2 }, { 91919, 2 }, { 91934, 2 }, { 92245, 1 }, { 92284, 2 }, { 92292, 4 }, { 92369, 3 }, { 92388, 2 }, { 92426, 7 }, { 92720, 14 }, { 92720, 6 }, { 92729, 9 }, { 92733, 13 }, { 92735, 6 }, { 92786, 2 }, { 92853, 31 }, { 92906, 2 }, { 93031, 7 }, { 93077, 2 },\n                { 93102, 2 }, { 93109, 2 }, { 93122, 3 }, { 93214, 2 }, { 93330, 2 }, { 93395, 2 }, { 93506, 2 }, { 93564, 9 }, { 93713, 9 }, { 93722, 4 }, { 93840, 2 }, { 93877, 4 }, { 93891, 3 }, { 93948, 2 }, { 93981, 2 }, { 94012, 3 }, { 94033, 2 }, { 94121, 2 }, { 94165, 32 }, { 94181, 3 }, { 94210, 2 }, { 94216, 2 }, { 94230, 2 },\n                { 94333, 31 }, { 94433, 3 }, { 94497, 3 }, { 94609, 2 }, { 94623, 2 }, { 94763, 2 }, { 94780, 2 }, { 95287, 2 }, { 95348, 2 }, { 95433, 5 }, { 95446, 2 }, { 95493, 7 }, { 95517, 3 }, { 95580, 2 }, { 95610, 5 }, { 95620, 2 }, { 95678, 3 }, { 95683, 2 }, { 95689, 2 }, { 95760, 2 }, { 95792, 2 }, { 95850, 2 }, { 95908, 2 },\n                { 95908, 2 }, { 95967, 2 }, { 96022, 3 }, { 96088, 2 }, { 96460, 2 }, { 96554, 2 }, { 96597, 2 }, { 96763, 2 }, { 96808, 2 }, { 96854, 1 }, { 96963, 1 }, { 97007, 3 }, { 97125, 1 }, { 97128, 2 }, { 97133, 3 }, { 97142, 3 }, { 97156, 2 }, { 97223, 2 }, { 97244, 2 }, { 97303, 2 }, { 97355, 2 }, { 97356, 3 }, { 97393, 3 },\n                { 97409, 1 }, { 97451, 2 }, { 97539, 2 }, { 97546, 2 }, { 97553, 2 }, { 97627, 2 }, { 97640, 2 }, { 97650, 6 }, { 97675, 2 }, { 97685, 3 }, { 97773, 2 }, { 97802, 4 }, { 97826, 19 }, { 97860, 2 }, { 97956, 2 }, { 97958, 2 }, { 97973, 3 }, { 97982, 2 }, { 98039, 2 }, { 98051, 2 }, { 98059, 2 }, { 98088, 2 }, { 98092, 4 },\n                { 98147, 2 }, { 98147, 2 }, { 98169, 2 }, { 98207, 2 }, { 98277, 1 }, { 98277, 22 }, { 98285, 2 }, { 98324, 3 }, { 98324, 3 }, { 98381, 31 }, { 98390, 2 }, { 98404, 2 }, { 98415, 4 }, { 98460, 2 }, { 98462, 1 }, { 98475, 3 }, { 98485, 2 }, { 98640, 1 }, { 98798, 2 }, { 98800, 4 }, { 98821, 2 }, { 98895, 2 }, { 98936, 2 },\n                { 98950, 2 }, { 98980, 2 }, { 99033, 2 }, { 99045, 2 }, { 99135, 2 }, { 99315, 30 }, { 99324, 2 }, { 99346, 2 }, { 99418, 2 }, { 99505, 2 }, { 99557, 2 }, { 99559, 2 }, { 99586, 2 }, { 99622, 2 }, { 99770, 1 }, { 99790, 2 }, { 99810, 2 }, { 99871, 1 }, { 99926, 2 }, { 99927, 2 }, { 99978, 2 }, { 99980, 2 }, { 100022, 3 },\n                { 100024, 1 }, { 100069, 2 }, { 100150, 2 }, { 100225, 2 }, { 100246, 1 }, { 100310, 2 }, { 100361, 2 }, { 100428, 1 }, { 100434, 2 }, { 100450, 4 }, { 100546, 2 }, { 100551, 2 }, { 100551, 2 }, { 100554, 1 }, { 100597, 2 }, { 100676, 2 }, { 100693, 2 }, { 100827, 2 }, { 100928, 2 }, { 100928, 1 }, { 100935, 2 }, { 100937, 3 },\n                { 101034, 2 }, { 101041, 2 }, { 101154, 2 }, { 101200, 4 }, { 101250, 2 }, { 101352, 2 }, { 101403, 2 }, { 101430, 1 }, { 101508, 3 }, { 101509, 3 }, { 101523, 10 }, { 101604, 2 }, { 101637, 2 }, { 101681, 4 }, { 101759, 1 }, { 101773, 1 }, { 101836, 1 }, { 101882, 4 }, { 101895, 2 }, { 101897, 2 }, { 101939, 2 }, { 101951, 6 },\n                { 101956, 5 }, { 102055, 1 }, { 102085, 2 }, { 102093, 2 }, { 102209, 2 }, { 102258, 6 }, { 102271, 2 }, { 102284, 2 }, { 102332, 2 }, { 102354, 2 }, { 102366, 2 }, { 102424, 3 }, { 102456, 2 }, { 102496, 1 }, { 102497, 3 }, { 102519, 3 }, { 102554, 1 }, { 102610, 5 }, { 102657, 2 }, { 102661, 4 }, { 102695, 4 }, { 102707, 12 },\n                { 102910, 2 }, { 102930, 5 }, { 102937, 9 }, { 102938, 7 }, { 102965, 6 }, { 102969, 7 }, { 103031, 2 }, { 103062, 2 }, { 103096, 2 }, { 103146, 2 }, { 103159, 2 }, { 103223, 2 }, { 103267, 2 }, { 103296, 2 }, { 103303, 2 }, { 103487, 2 }, { 103491, 2 }, { 103599, 2 }, { 103677, 2 }, { 103903, 1 }, { 104040, 2 }, { 104047, 1 },\n                { 104052, 2 }, { 104057, 4 }, { 104057, 2 }, { 104062, 4 }, { 104091, 2 }, { 104189, 3 }, { 104283, 8 }, { 104288, 4 }, { 104305, 3 }, { 104445, 2 }, { 104472, 2 }, { 104475, 1 }, { 104497, 4 }, { 104548, 2 }, { 104582, 2 }, { 104626, 1 }, { 104716, 2 }, { 104826, 2 }, { 104849, 2 }, { 104872, 1 }, { 104945, 1 }, { 104948, 2 },\n                { 105066, 2 }, { 105071, 1 }, { 105198, 4 }, { 105198, 4 }, { 105203, 2 }, { 105256, 6 }, { 105263, 2 }, { 105329, 2 }, { 105515, 2 }, { 105566, 2 }, { 105566, 2 }, { 105585, 2 }, { 105678, 2 }, { 105852, 2 }, { 105877, 2 }, { 105911, 2 }, { 106022, 1 }, { 106033, 2 }, { 106080, 2 }, { 106192, 2 }, { 106220, 3 }, { 106243, 2 },\n                { 106323, 11 }, { 106371, 2 }, { 106608, 2 }, { 106624, 2 }, { 106680, 3 }, { 106688, 1 }, { 106800, 1 }, { 106800, 1 }, { 106821, 4 }, { 106853, 1 }, { 106930, 3 }, { 106937, 2 }, { 106955, 2 }, { 106996, 2 }, { 106996, 1 }, { 107148, 4 }, { 107213, 16 }, { 107213, 2 }, { 107243, 2 }, { 107360, 2 }, { 107408, 2 }, { 107509, 4 },\n                { 107572, 2 }, { 107592, 2 }, { 107644, 5 }, { 107679, 2 }, { 107705, 3 }, { 107761, 4 }, { 107780, 2 }, { 107825, 2 }, { 108007, 2 }, { 108041, 4 }, { 108058, 2 }, { 108071, 1 }, { 108132, 2 }, { 108164, 2 }, { 108189, 2 }, { 108210, 2 }, { 108330, 2 }, { 108430, 2 }, { 108450, 2 }, { 108469, 2 }, { 108484, 2 }, { 108533, 2 },\n                { 108588, 2 }, { 108594, 2 }, { 108690, 2 }, { 108785, 1 }, { 108814, 2 }, { 108818, 1 }, { 108820, 2 }, { 108889, 2 }, { 108951, 2 }, { 108959, 2 }, { 108963, 2 }, { 109034, 2 }, { 109172, 1 }, { 109176, 2 }, { 109195, 3 }, { 109229, 2 }, { 109256, 2 }, { 109290, 2 }, { 109304, 2 }, { 109333, 2 }, { 109343, 4 }, { 109347, 7 },\n                { 109387, 2 }, { 109421, 1 }, { 109497, 2 }, { 109501, 3 }, { 109513, 2 }, { 109525, 3 }, { 109625, 4 }, { 109710, 2 }, { 109740, 2 }, { 109751, 2 }, { 109761, 2 }, { 109890, 8 }, { 109891, 4 }, { 109909, 2 }, { 109923, 1 }, { 110017, 2 }, { 110046, 2 }, { 110111, 2 }, { 110258, 2 }, { 110340, 2 }, { 110352, 2 }, { 110398, 2 },\n                { 110583, 2 }, { 110600, 13 }, { 110626, 3 }, { 110709, 2 }, { 110772, 4 }, { 110773, 2 }, { 110813, 1 }, { 110890, 2 }, { 110898, 2 }, { 110954, 2 }, { 111120, 2 }, { 111132, 3 }, { 111163, 8 }, { 111224, 2 }, { 111340, 2 }, { 111398, 2 }, { 111555, 2 }, { 111597, 3 }, { 111607, 2 }, { 111655, 2 }, { 111691, 3 }, { 111835, 2 },\n                { 111854, 2 }, { 111876, 16 }, { 111884, 1 }, { 111884, 2 }, { 111929, 2 }, { 111941, 2 }, { 111969, 2 }, { 112003, 2 }, { 112165, 2 }, { 112365, 2 }, { 112450, 1 }, { 112521, 2 }, { 112649, 4 }, { 112665, 2 }, { 112881, 1 }, { 112882, 2 }, { 112906, 2 }, { 112951, 2 }, { 112994, 2 }, { 112997, 2 }, { 113002, 2 }, { 113056, 1 },\n                { 113077, 2 }, { 113208, 1 }, { 113320, 2 }, { 113326, 3 }, { 113375, 2 }, { 113530, 30 }, { 113530, 30 }, { 113537, 1 }, { 113563, 14 }, { 113592, 2 }, { 113637, 2 }, { 113768, 2 }, { 113850, 5 }, { 113892, 2 }, { 113916, 2 }, { 113965, 2 }, { 113976, 2 }, { 114037, 2 }, { 114149, 1 }, { 114158, 9 }, { 114201, 2 }, { 114262, 2 },\n                { 114268, 4 }, { 114353, 2 }, { 114388, 2 }, { 114404, 2 }, { 114428, 5 }, { 114438, 2 }, { 114541, 2 }, { 114550, 2 }, { 114561, 2 }, { 114625, 3 }, { 114730, 2 }, { 114770, 1 }, { 114815, 4 }, { 114998, 2 }, { 115077, 2 }, { 115093, 2 }, { 115120, 2 }, { 115194, 2 }, { 115216, 3 }, { 115299, 2 }, { 115391, 3 }, { 115410, 2 },\n                { 115542, 33 }, { 115581, 2 }, { 115618, 2 }, { 115645, 5 }, { 115647, 2 }, { 115697, 2 }, { 115725, 2 }, { 115740, 2 }, { 115757, 2 }, { 115763, 2 }, { 115770, 2 }, { 115787, 2 }, { 115916, 2 }, { 115928, 2 }, { 115962, 2 }, { 116020, 2 }, { 116022, 1 }, { 116089, 2 }, { 116159, 1 }, { 116196, 2 }, { 116247, 2 }, { 116254, 7 },\n                { 116336, 2 }, { 116409, 2 }, { 116459, 2 }, { 116569, 2 }, { 116619, 2 }, { 116688, 2 }, { 116733, 2 }, { 116807, 3 }, { 116843, 2 }, { 116886, 1 }, { 116902, 2 }, { 116931, 2 }, { 116952, 2 }, { 116952, 2 }, { 117177, 2 }, { 117189, 2 }, { 117206, 2 }, { 117260, 29 }, { 117271, 6 }, { 117276, 3 }, { 117276, 5 }, { 117278, 3 },\n                { 117278, 2 }, { 117359, 4 }, { 117380, 2 }, { 117414, 1 }, { 117503, 2 }, { 117517, 2 }, { 117530, 2 }, { 117574, 4 }, { 117575, 5 }, { 117577, 2 }, { 117606, 2 }, { 117645, 2 }, { 117655, 2 }, { 117692, 2 }, { 117705, 1 }, { 117731, 1 }, { 117762, 4 }, { 117780, 2 }, { 117974, 1 }, { 118057, 1 }, { 118099, 2 }, { 118107, 2 },\n                { 118113, 2 }, { 118175, 2 }, { 118198, 2 }, { 118232, 2 }, { 118326, 1 }, { 118438, 31 }, { 118469, 2 }, { 118521, 31 }, { 118565, 2 }, { 118593, 2 }, { 118602, 2 }, { 118652, 2 }, { 118668, 2 }, { 118689, 3 }, { 118703, 14 }, { 118705, 2 }, { 118813, 2 }, { 118825, 2 }, { 118894, 3 }, { 118915, 2 }, { 118962, 2 }, { 118986, 2 },\n                { 119045, 2 }, { 119054, 1 }, { 119054, 1 }, { 119119, 2 }, { 119149, 2 }, { 119206, 1 }, { 119316, 2 }, { 119387, 2 }, { 119404, 3 }, { 119516, 2 }, { 119520, 2 }, { 119571, 3 }, { 119573, 2 }, { 119610, 5 }, { 119621, 2 }, { 119623, 4 }, { 119672, 2 }, { 119692, 3 }, { 119734, 2 }, { 119742, 1 }, { 119754, 1 }, { 119785, 2 },\n                { 120001, 2 }, { 120115, 4 }, { 120260, 2 }, { 120314, 2 }, { 120416, 2 }, { 120435, 1 }, { 120450, 3 }, { 120530, 2 }, { 120550, 5 }, { 120730, 2 }, { 120731, 2 }, { 120751, 3 }, { 120755, 2 }, { 120869, 2 }, { 120988, 2 }, { 121061, 2 }, { 121177, 2 }, { 121212, 2 }, { 121214, 1 }, { 121286, 2 }, { 121331, 1 }, { 121344, 2 },\n                { 121407, 2 }, { 121424, 1 }, { 121491, 2 }, { 121568, 1 }, { 121588, 6 }, { 121651, 2 }, { 121676, 2 }, { 121785, 4 }, { 121830, 3 }, { 121919, 1 }, { 121951, 2 }, { 121991, 1 }, { 122056, 2 }, { 122062, 2 }, { 122144, 2 }, { 122183, 1 }, { 122331, 2 }, { 122466, 2 }, { 122558, 2 }, { 122570, 2 }, { 122676, 2 }, { 122733, 2 },\n                { 122774, 6 }, { 122783, 2 }, { 122825, 2 }, { 122865, 2 }, { 122884, 2 }, { 122892, 2 }, { 122911, 2 }, { 122929, 2 }, { 122936, 2 }, { 123190, 2 }, { 123271, 2 }, { 123271, 2 }, { 123302, 7 }, { 123391, 2 }, { 123394, 2 }, { 123416, 1 }, { 123708, 2 }, { 123752, 2 }, { 123761, 2 }, { 123783, 2 }, { 123794, 2 }, { 123817, 2 },\n                { 123820, 1 }, { 123823, 1 }, { 123857, 3 }, { 123886, 2 }, { 124023, 1 }, { 124029, 2 }, { 124042, 2 }, { 124056, 3 }, { 124071, 6 }, { 124105, 5 }, { 124143, 2 }, { 124191, 2 }, { 124207, 1 }, { 124257, 2 }, { 124306, 3 }, { 124338, 2 }, { 124388, 8 }, { 124400, 2 }, { 124418, 2 }, { 124502, 2 }, { 124521, 1 }, { 124533, 2 },\n                { 124645, 2 }, { 124685, 1 }, { 124694, 2 }, { 124700, 1 }, { 124736, 2 }, { 124891, 7 }, { 124920, 2 }, { 124983, 2 }, { 125014, 2 }, { 125038, 2 }, { 125084, 2 }, { 125162, 2 }, { 125193, 2 }, { 125285, 2 }, { 125368, 2 }, { 125409, 2 }, { 125570, 2 }, { 125601, 2 }, { 125641, 1 }, { 125721, 2 }, { 125731, 2 }, { 125803, 2 },\n                { 125904, 2 }, { 125973, 2 }, { 126018, 1 }, { 126034, 5 }, { 126094, 1 }, { 126144, 1 }, { 126195, 2 }, { 126297, 2 }, { 126389, 2 }, { 126429, 2 }, { 126439, 2 }, { 126499, 2 }, { 126501, 1 }, { 126587, 2 }, { 126663, 2 }, { 126681, 2 }, { 126687, 1 }, { 126781, 2 }, { 126783, 2 }, { 126840, 8 }, { 126843, 2 }, { 126959, 2 },\n                { 127015, 2 }, { 127101, 2 }, { 127149, 2 }, { 127197, 3 }, { 127268, 2 }, { 127372, 2 }, { 127385, 2 }, { 127473, 4 }, { 127539, 2 }, { 127598, 2 }, { 127613, 14 }, { 127683, 3 }, { 127684, 2 }, { 127697, 2 }, { 127698, 3 }, { 127773, 2 }, { 127781, 1 }, { 127839, 2 }, { 127905, 2 }, { 127949, 2 }, { 128035, 2 }, { 128046, 1 },\n                { 128167, 2 }, { 128271, 2 }, { 128307, 1 }, { 128320, 2 }, { 128330, 2 }, { 128375, 2 }, { 128381, 4 }, { 128447, 2 }, { 128462, 2 }, { 128466, 3 }, { 128466, 2 }, { 128496, 2 }, { 128589, 2 }, { 128616, 3 }, { 128679, 1 }, { 128770, 1 }, { 128793, 2 }, { 128802, 2 }, { 128813, 2 }, { 128900, 2 }, { 128949, 2 }, { 129269, 2 },\n                { 129271, 3 }, { 129278, 2 }, { 129343, 1 }, { 129408, 2 }, { 129408, 1 }, { 129421, 6 }, { 129461, 2 }, { 129469, 3 }, { 129482, 2 }, { 129502, 2 }, { 129512, 2 }, { 129551, 2 }, { 129629, 2 }, { 129632, 2 }, { 129679, 1 }, { 129725, 2 }, { 130007, 2 }, { 130018, 16 }, { 130057, 2 }, { 130071, 2 }, { 130087, 2 }, { 130188, 1 },\n                { 130202, 2 }, { 130316, 2 }, { 130328, 1 }, { 130466, 2 }, { 130549, 2 }, { 130649, 2 }, { 130705, 3 }, { 130800, 2 }, { 130907, 2 }, { 130989, 2 }, { 131103, 2 }, { 131127, 2 }, { 131200, 5 }, { 131241, 6 }, { 131351, 2 }, { 131413, 2 }, { 131448, 2 }, { 131599, 2 }, { 131634, 1 }, { 131687, 2 }, { 131739, 2 }, { 131758, 2 },\n                { 131765, 2 }, { 131787, 3 }, { 131819, 3 }, { 131868, 2 }, { 131886, 2 }, { 131901, 4 }, { 131977, 2 }, { 131990, 2 }, { 132035, 2 }, { 132035, 2 }, { 132043, 2 }, { 132173, 2 }, { 132181, 4 }, { 132181, 6 }, { 132194, 5 }, { 132252, 2 }, { 132262, 6 }, { 132271, 1 }, { 132285, 2 }, { 132328, 2 }, { 132335, 1 }, { 132337, 1 },\n                { 132389, 5 }, { 132430, 2 }, { 132451, 2 }, { 132499, 4 }, { 132503, 1 }, { 132520, 4 }, { 132541, 4 }, { 132860, 2 }, { 132862, 4 }, { 132874, 12 }, { 132874, 13 }, { 132875, 12 }, { 132911, 2 }, { 132973, 2 }, { 133051, 2 }, { 133062, 2 }, { 133067, 2 }, { 133138, 2 }, { 133184, 2 }, { 133231, 2 }, { 133297, 3 }, { 133344, 2 },\n                { 133385, 4 }, { 133408, 2 }, { 133464, 2 }, { 133522, 2 }, { 133631, 2 }, { 133631, 2 }, { 133702, 2 }, { 133705, 1 }, { 133721, 2 }, { 133746, 2 }, { 133773, 3 }, { 133819, 2 }, { 133843, 2 }, { 133929, 2 }, { 133946, 2 }, { 134113, 4 }, { 134151, 2 }, { 134289, 1 }, { 134385, 2 }, { 134429, 2 }, { 134506, 2 }, { 134511, 2 },\n                { 134521, 2 }, { 134558, 1 }, { 134710, 2 }, { 134738, 2 }, { 134751, 3 }, { 134818, 2 }, { 134820, 4 }, { 134879, 2 }, { 134919, 2 }, { 134947, 2 }, { 134948, 3 }, { 135040, 3 }, { 135125, 10 }, { 135155, 2 }, { 135228, 2 }, { 135255, 2 }, { 135296, 3 }, { 135322, 2 }, { 135349, 2 }, { 135428, 3 }, { 135476, 1 }, { 135503, 2 },\n                { 135524, 2 }, { 135550, 4 }, { 135594, 2 }, { 135597, 2 }, { 135624, 3 }, { 135741, 2 }, { 135753, 2 }, { 135842, 2 }, { 135853, 2 }, { 135896, 3 }, { 136004, 1 }, { 136061, 1 }, { 136068, 1 }, { 136106, 2 }, { 136145, 2 }, { 136145, 2 }, { 136173, 2 }, { 136186, 2 }, { 136196, 2 }, { 136201, 2 }, { 136211, 2 }, { 136268, 2 },\n                { 136298, 2 }, { 136377, 2 }, { 136420, 2 }, { 136475, 2 }, { 136486, 1 }, { 136554, 2 }, { 136641, 2 }, { 136770, 1 }, { 136873, 2 }, { 136877, 1 }, { 136906, 2 }, { 137092, 2 }, { 137143, 2 }, { 137200, 3 }, { 137232, 2 }, { 137239, 2 }, { 137248, 2 }, { 137281, 1 }, { 137301, 2 }, { 137314, 3 }, { 137352, 1 }, { 137365, 2 },\n                { 137375, 2 }, { 137411, 2 }, { 137424, 2 }, { 137516, 2 }, { 137532, 2 }, { 137593, 2 }, { 137600, 2 }, { 137658, 2 }, { 137703, 2 }, { 137766, 2 }, { 137791, 2 }, { 137801, 2 }, { 137864, 2 }, { 137870, 3 }, { 137931, 2 }, { 138009, 3 }, { 138013, 1 }, { 138013, 1 }, { 138066, 2 }, { 138073, 2 }, { 138114, 2 }, { 138150, 2 },\n                { 138236, 2 }, { 138276, 2 }, { 138286, 2 }, { 138298, 3 }, { 138309, 1 }, { 138373, 3 }, { 138524, 2 }, { 138535, 1 }, { 138593, 4 }, { 138611, 1 }, { 138725, 2 }, { 138807, 2 }, { 138819, 3 }, { 138849, 5 }, { 138867, 2 }, { 138907, 2 }, { 138930, 3 }, { 139026, 2 }, { 139102, 2 }, { 139108, 3 }, { 139184, 1 }, { 139209, 3 },\n                { 139282, 2 }, { 139289, 4 }, { 139382, 1 }, { 139421, 1 }, { 139436, 2 }, { 139450, 1 }, { 139523, 3 }, { 139533, 2 }, { 139590, 2 }, { 139590, 2 }, { 139722, 2 }, { 139785, 2 }, { 139785, 1 }, { 139798, 2 }, { 139813, 2 }, { 139868, 2 }, { 139935, 3 }, { 139990, 3 }, { 140050, 2 }, { 140177, 2 }, { 140177, 4 }, { 140408, 2 },\n                { 140420, 3 }, { 140461, 2 }, { 140578, 15 }, { 140605, 1 }, { 140662, 1 }, { 140755, 2 }, { 140786, 2 }, { 140846, 2 }, { 140874, 2 }, { 140959, 1 }, { 140973, 2 }, { 141128, 2 }, { 141132, 2 }, { 141257, 2 }, { 141290, 1 }, { 141360, 2 }, { 141472, 2 }, { 141545, 2 }, { 141545, 2 }, { 141575, 1 }, { 141606, 5 }, { 141655, 2 },\n                { 141735, 2 }, { 141767, 5 }, { 141796, 2 }, { 141841, 2 }, { 141915, 2 }, { 141923, 1 }, { 141932, 2 }, { 141994, 2 }, { 142018, 2 }, { 142029, 3 }, { 142072, 2 }, { 142128, 2 }, { 142133, 1 }, { 142261, 2 }, { 142304, 1 }, { 142400, 2 }, { 142401, 2 }, { 142409, 2 }, { 142479, 2 }, { 142522, 1 }, { 142552, 1 }, { 142589, 2 },\n                { 142596, 2 }, { 142753, 1 }, { 142766, 2 }, { 142796, 2 }, { 142836, 2 }, { 142871, 2 }, { 143058, 3 }, { 143059, 6 }, { 143063, 3 }, { 143065, 2 }, { 143141, 4 }, { 143173, 2 }, { 143374, 2 }, { 143399, 2 }, { 143406, 2 }, { 143429, 3 }, { 143430, 2 }, { 143462, 1 }, { 143579, 2 }, { 143663, 2 }, { 143844, 3 }, { 143851, 2 },\n                { 143926, 2 }, { 143931, 2 }, { 144051, 6 }, { 144085, 10 }, { 144147, 2 }, { 144188, 4 }, { 144238, 4 }, { 144353, 2 }, { 144465, 2 }, { 144474, 2 }, { 144637, 2 }, { 144638, 1 }, { 144648, 1 }, { 144661, 3 }, { 144812, 2 }, { 144847, 2 }, { 144901, 8 }, { 145058, 2 }, { 145122, 8 }, { 145134, 2 }, { 145150, 2 }, { 145299, 1 },\n                { 145313, 2 }, { 145314, 3 }, { 145374, 2 }, { 145412, 2 }, { 145432, 2 }, { 145446, 2 }, { 145534, 3 }, { 145592, 2 }, { 145614, 2 }, { 145648, 2 }, { 145721, 2 }, { 145858, 1 }, { 145970, 3 }, { 145984, 3 }, { 146004, 2 }, { 146016, 3 }, { 146048, 2 }, { 146097, 3 }, { 146103, 2 }, { 146136, 2 }, { 146194, 3 }, { 146230, 1 },\n                { 146254, 2 }, { 146261, 4 }, { 146269, 4 }, { 146393, 2 }, { 146411, 3 }, { 146501, 2 }, { 146547, 2 }, { 146547, 2 }, { 146573, 2 }, { 146616, 2 }, { 146622, 3 }, { 146728, 3 }, { 146781, 5 }, { 146805, 4 }, { 146921, 2 }, { 147002, 3 }, { 147072, 2 }, { 147159, 2 }, { 147170, 2 }, { 147203, 1 }, { 147245, 2 }, { 147278, 2 },\n                { 147422, 2 }, { 147471, 2 }, { 147491, 2 }, { 147607, 4 }, { 147693, 2 }, { 147763, 2 }, { 147775, 6 }, { 147776, 4 }, { 147824, 2 }, { 147922, 2 }, { 147922, 2 }, { 147937, 2 }, { 147957, 2 }, { 147980, 2 }, { 148008, 2 }, { 148018, 2 }, { 148046, 3 }, { 148071, 4 }, { 148106, 3 }, { 148122, 2 }, { 148139, 2 }, { 148175, 2 },\n                { 148318, 2 }, { 148514, 2 }, { 148528, 2 }, { 148539, 2 }, { 148545, 2 }, { 148564, 2 }, { 148569, 2 }, { 148607, 3 }, { 148712, 2 }, { 148751, 2 }, { 148792, 4 }, { 148807, 2 }, { 148818, 2 }, { 148846, 9 }, { 148848, 2 }, { 148851, 2 }, { 148861, 3 }, { 148924, 32 }, { 148934, 2 }, { 149037, 1 }, { 149127, 3 }, { 149132, 2 },\n                { 149181, 1 }, { 149181, 2 }, { 149206, 2 }, { 149216, 7 }, { 149240, 4 }, { 149240, 1 }, { 149279, 1 }, { 149280, 3 }, { 149292, 2 }, { 149314, 2 }, { 149344, 2 }, { 149364, 4 }, { 149388, 2 }, { 149438, 2 }, { 149520, 2 }, { 149566, 2 }, { 149630, 2 }, { 149682, 2 }, { 149691, 1 }, { 149703, 2 }, { 149775, 2 }, { 149796, 1 },\n                { 149863, 1 }, { 149884, 2 }, { 149888, 1 }, { 149983, 2 }, { 150078, 3 }, { 150083, 6 }, { 150175, 1 }, { 150235, 2 }, { 150238, 2 }, { 150298, 3 }, { 150321, 2 }, { 150382, 2 }, { 150510, 4 }, { 150574, 2 }, { 150619, 5 }, { 150645, 2 }, { 150694, 2 }, { 150732, 8 }, { 150764, 2 }, { 150813, 2 }, { 150871, 2 }, { 150879, 2 },\n                { 150888, 1 }, { 150920, 2 }, { 151009, 2 }, { 151013, 2 }, { 151019, 2 }, { 151063, 2 }, { 151067, 2 }, { 151125, 1 }, { 151151, 5 }, { 151172, 2 }, { 151197, 4 }, { 151228, 70 }, { 151292, 2 }, { 151354, 2 }, { 151392, 2 }, { 151396, 1 }, { 151412, 2 }, { 151514, 2 }, { 151529, 2 }, { 151567, 2 }, { 151589, 2 }, { 151641, 2 },\n                { 151672, 2 }, { 151730, 2 }, { 151748, 2 }, { 151770, 1 }, { 151788, 2 }, { 151795, 2 }, { 151805, 2 }, { 152046, 5 }, { 152048, 3 }, { 152054, 2 }, { 152057, 3 }, { 152058, 2 }, { 152075, 2 }, { 152090, 9 }, { 152205, 2 }, { 152440, 2 }, { 152480, 2 }, { 152484, 2 }, { 152601, 2 }, { 152714, 2 }, { 152801, 2 }, { 152819, 10 },\n                { 152825, 2 }, { 152896, 10 }, { 152937, 2 }, { 152938, 2 }, { 152939, 3 }, { 153042, 2 }, { 153069, 2 }, { 153099, 2 }, { 153164, 2 }, { 153234, 2 }, { 153266, 2 }, { 153345, 2 }, { 153420, 2 }, { 153479, 2 }, { 153488, 4 }, { 153502, 2 }, { 153663, 3 }, { 153740, 1 }, { 153780, 2 }, { 153824, 6 }, { 153938, 2 }, { 153985, 2 },\n                { 154022, 2 }, { 154022, 1 }, { 154072, 4 }, { 154109, 2 }, { 154189, 2 }, { 154222, 2 }, { 154228, 2 }, { 154265, 15 }, { 154324, 2 }, { 154350, 2 }, { 154375, 2 }, { 154396, 2 }, { 154431, 2 }, { 154463, 2 }, { 154475, 3 }, { 154510, 1 }, { 154518, 1 }, { 154529, 2 }, { 154710, 2 }, { 154742, 2 }, { 154792, 2 }, { 154871, 4 },\n                { 154960, 2 }, { 154961, 2 }, { 154964, 2 }, { 154989, 3 }, { 155002, 3 }, { 155079, 2 }, { 155105, 2 }, { 155107, 2 }, { 155258, 1 }, { 155328, 2 }, { 155328, 2 }, { 155347, 2 }, { 155369, 2 }, { 155447, 2 }, { 155482, 2 }, { 155508, 2 }, { 155531, 2 }, { 155553, 1 }, { 155647, 3 }, { 155659, 9 }, { 155859, 2 }, { 155960, 2 },\n                { 156009, 2 }, { 156062, 2 }, { 156143, 3 }, { 156217, 3 }, { 156252, 7 }, { 156260, 2 }, { 156274, 2 }, { 156339, 2 }, { 156354, 3 }, { 156406, 2 }, { 156550, 2 }, { 156694, 2 }, { 156730, 12 }, { 156795, 4 }, { 156806, 3 }, { 156818, 5 }, { 156835, 3 }, { 156850, 3 }, { 156861, 4 }, { 156877, 2 }, { 156915, 6 }, { 156967, 2 },\n                { 157046, 2 }, { 157208, 3 }, { 157260, 2 }, { 157364, 2 }, { 157365, 1 }, { 157371, 2 }, { 157440, 2 }, { 157453, 2 }, { 157482, 1 }, { 157505, 2 }, { 157511, 4 }, { 157522, 2 }, { 157562, 2 }, { 157562, 2 }, { 157702, 2 }, { 157734, 3 }, { 157807, 2 }, { 157851, 2 }, { 157882, 2 }, { 157957, 2 }, { 158227, 2 }, { 158284, 2 },\n                { 158292, 2 }, { 158310, 3 }, { 158310, 3 }, { 158330, 2 }, { 158358, 1 }, { 158493, 2 }, { 158596, 2 }, { 158736, 2 }, { 158812, 1 }, { 158830, 2 }, { 158846, 1 }, { 158884, 1 }, { 158918, 2 }, { 159003, 2 }, { 159056, 2 }, { 159189, 2 }, { 159372, 2 }, { 159373, 2 }, { 159410, 3 }, { 159421, 4 }, { 159429, 2 }, { 159505, 2 },\n                { 159559, 1 }, { 159574, 2 }, { 159587, 4 }, { 159683, 2 }, { 159745, 1 }, { 159748, 3 }, { 159858, 2 }, { 159945, 1 }, { 159971, 4 }, { 159982, 2 }, { 160079, 13 }, { 160084, 2 }, { 160085, 4 }, { 160104, 9 }, { 160197, 2 }, { 160295, 2 }, { 160365, 2 }, { 160372, 1 }, { 160392, 3 }, { 160408, 1 }, { 160446, 1 }, { 160540, 2 },\n                { 160599, 1 }, { 160604, 2 }, { 160745, 3 }, { 160752, 2 }, { 160794, 2 }, { 160826, 2 }, { 160846, 2 }, { 160871, 2 }, { 160957, 2 }, { 160986, 2 }, { 161053, 2 }, { 161133, 3 }, { 161133, 1 }, { 161162, 3 }, { 161247, 2 }, { 161270, 2 }, { 161292, 6 }, { 161370, 2 }, { 161420, 2 }, { 161446, 2 }, { 161487, 2 }, { 161511, 3 },\n                { 161512, 1 }, { 161580, 2 }, { 161782, 12 }, { 161784, 8 }, { 161786, 2 }, { 161786, 8 }, { 161787, 7 }, { 161795, 2 }, { 161825, 7 }, { 161833, 4 }, { 161892, 2 }, { 161930, 2 }, { 161992, 2 }, { 162054, 2 }, { 162176, 2 }, { 162183, 2 }, { 162219, 2 }, { 162245, 2 }, { 162288, 2 }, { 162361, 3 }, { 162370, 2 }, { 162388, 2 },\n                { 162434, 2 }, { 162447, 2 }, { 162524, 2 }, { 162542, 3 }, { 162562, 2 }, { 162594, 2 }, { 162646, 1 }, { 162662, 2 }, { 162761, 2 }, { 162780, 2 }, { 162802, 2 }, { 162820, 3 }, { 162824, 2 }, { 162908, 2 }, { 162968, 2 }, { 163171, 2 }, { 163190, 2 }, { 163288, 1 }, { 163288, 1 }, { 163397, 2 }, { 163405, 6 }, { 163414, 1 },\n                { 163506, 1 }, { 163558, 2 }, { 163565, 1 }, { 163568, 3 }, { 163619, 2 }, { 163633, 2 }, { 163678, 2 }, { 163745, 3 }, { 163765, 4 }, { 163773, 2 }, { 163793, 2 }, { 163878, 7 }, { 163949, 2 }, { 163975, 2 }, { 163991, 2 }, { 164016, 2 }, { 164020, 3 }, { 164068, 1 }, { 164076, 4 }, { 164082, 3 }, { 164176, 2 }, { 164236, 2 },\n                { 164238, 1 }, { 164315, 2 }, { 164449, 2 }, { 164529, 2 }, { 164574, 4 }, { 164591, 2 }, { 164595, 2 }, { 164611, 2 }, { 164623, 4 }, { 164632, 10 }, { 164691, 2 }, { 164706, 2 }, { 164755, 2 }, { 164761, 2 }, { 164973, 2 }, { 165030, 2 }, { 165090, 2 }, { 165099, 1 }, { 165126, 2 }, { 165188, 2 }, { 165205, 2 }, { 165275, 1 },\n                { 165347, 2 }, { 165381, 2 }, { 165562, 2 }, { 165563, 1 }, { 165594, 2 }, { 165641, 2 }, { 165663, 6 }, { 165759, 2 }, { 165811, 2 }, { 165822, 1 }, { 165830, 1 }, { 165903, 1 }, { 165921, 2 }, { 165953, 1 }, { 166022, 1 }, { 166294, 2 }, { 166333, 2 }, { 166420, 2 }, { 166433, 2 }, { 166442, 1 }, { 166536, 2 }, { 166543, 2 },\n                { 166556, 2 }, { 166571, 2 }, { 166575, 1 }, { 166588, 2 }, { 166601, 2 }, { 166663, 3 }, { 166692, 1 }, { 166710, 2 }, { 166759, 2 }, { 166785, 3 }, { 166842, 2 }, { 166843, 2 }, { 166864, 2 }, { 166902, 2 }, { 166996, 2 }, { 166999, 2 }, { 167038, 2 }, { 167112, 4 }, { 167112, 2 }, { 167177, 2 }, { 167180, 2 }, { 167229, 1 },\n                { 167298, 2 }, { 167306, 4 }, { 167309, 3 }, { 167402, 2 }, { 167405, 2 }, { 167433, 2 }, { 167435, 1 }, { 167461, 3 }, { 167553, 3 }, { 167688, 5 }, { 167689, 2 }, { 167709, 2 }, { 167744, 2 }, { 167821, 2 }, { 167825, 2 }, { 167925, 10 }, { 167969, 2 }, { 168024, 2 }, { 168089, 2 }, { 168104, 2 }, { 168194, 2 }, { 168305, 2 },\n                { 168316, 2 }, { 168366, 2 }, { 168423, 2 }, { 168568, 3 }, { 168582, 2 }, { 168615, 3 }, { 168618, 2 }, { 168638, 2 }, { 168671, 2 }, { 168736, 2 }, { 168747, 2 }, { 168750, 4 }, { 168808, 3 }, { 168814, 4 }, { 168820, 2 }, { 168914, 2 }, { 168968, 2 }, { 168979, 2 }, { 169006, 2 }, { 169069, 2 }, { 169106, 3 }, { 169158, 2 },\n                { 169158, 2 }, { 169189, 2 }, { 169253, 2 }, { 169259, 1 }, { 169279, 1 }, { 169325, 8 }, { 169349, 2 }, { 169353, 2 }, { 169378, 2 }, { 169432, 2 }, { 169476, 1 }, { 169476, 1 }, { 169525, 2 }, { 169538, 7 }, { 169555, 2 }, { 169571, 2 }, { 169594, 4 }, { 169687, 2 }, { 169799, 2 }, { 169831, 2 }, { 170042, 2 }, { 170061, 2 },\n                { 170065, 1 }, { 170128, 6 }, { 170148, 20 }, { 170215, 70 }, { 170256, 60 }, { 170266, 69 }, { 170275, 7 }, { 170277, 6 }, { 170500, 3 }, { 170516, 3 }, { 170601, 2 }, { 170666, 2 }, { 170668, 4 }, { 170668, 1 }, { 170716, 3 }, { 170728, 3 }, { 170735, 5 }, { 170847, 3 }, { 170852, 9 }, { 170858, 2 }, { 170859, 3 }, { 170956, 2 },\n                { 170956, 1 }, { 170967, 2 }, { 171005, 2 }, { 171113, 2 }, { 171279, 2 }, { 171400, 2 }, { 171405, 2 }, { 171448, 1 }, { 171490, 2 }, { 171567, 32 }, { 171590, 2 }, { 171723, 2 }, { 171737, 3 }, { 171958, 2 }, { 171967, 2 }\n        };\n    }\n\n    /* sub-class to avoid 65k limit of a single class */\n    private static class SampleDataHolder2 {\n        /*\n         * Array of [milliseconds, latency]\n         */\n        private static int[][] data = new int[][] { { 0, 3 }, { 43, 33 }, { 45, 11 }, { 45, 1 }, { 68, 13 }, { 88, 10 }, { 158, 68 }, { 158, 4 }, { 169, 168 }, { 267, 68 }, { 342, 68 }, { 438, 68 }, { 464, 7 }, { 504, 68 }, { 541, 6 }, { 541, 68 }, { 562, 68 }, { 581, 3 }, { 636, 68 }, { 778, 68 }, { 825, 1 }, { 859, 68 },\n                { 948, 1 }, { 1043, 68 }, { 1145, 68 }, { 1152, 1 }, { 1218, 5 }, { 1229, 68 }, { 1259, 68 }, { 1333, 68 }, { 1349, 68 }, { 1392, 68 }, { 1468, 1 }, { 1551, 68 }, { 1586, 68 }, { 1685, 68 }, { 1696, 1 }, { 1807, 68 }, { 1817, 3 }, { 1817, 6 }, { 1847, 68 }, { 1870, 68 }, { 1939, 68 }, { 2050, 68 }, { 2129, 3 }, { 2141, 68 },\n                { 2265, 68 }, { 2414, 1 }, { 2693, 68 }, { 2703, 68 }, { 2791, 68 }, { 2838, 68 }, { 2906, 68 }, { 2981, 68 }, { 3008, 68 }, { 3026, 4 }, { 3077, 68 }, { 3273, 68 }, { 3282, 68 }, { 3286, 68 }, { 3318, 3 }, { 3335, 5 }, { 3710, 68 }, { 3711, 1 }, { 3745, 68 }, { 3748, 4 }, { 3767, 3 }, { 3809, 3 }, { 3835, 35 }, { 4083, 1 },\n                { 4116, 68 }, { 4117, 1 }, { 4157, 1 }, { 4279, 68 }, { 4344, 68 }, { 4452, 68 }, { 4530, 68 }, { 4583, 68 }, { 4647, 3 }, { 4758, 68 }, { 4776, 68 }, { 4793, 68 }, { 4901, 68 }, { 4909, 68 }, { 4962, 68 }, { 4984, 68 }, { 5022, 68 }, { 5139, 68 }, { 5166, 1 }, { 5174, 68 }, { 5187, 68 }, { 5225, 68 }, { 5234, 68 }, { 5263, 1 },\n                { 5325, 68 }, { 5355, 4 }, { 5407, 1 }, { 5414, 68 }, { 5589, 68 }, { 5595, 68 }, { 5747, 68 }, { 5780, 68 }, { 5788, 68 }, { 5796, 68 }, { 5818, 68 }, { 5975, 1 }, { 6018, 1 }, { 6270, 68 }, { 6272, 68 }, { 6348, 68 }, { 6372, 68 }, { 6379, 68 }, { 6439, 68 }, { 6442, 68 }, { 6460, 68 }, { 6460, 68 }, { 6509, 68 }, { 6511, 1 },\n                { 6514, 4 }, { 6530, 8 }, { 6719, 68 }, { 6760, 68 }, { 6784, 68 }, { 6838, 1 }, { 6861, 68 }, { 6947, 68 }, { 7013, 68 }, { 7075, 68 }, { 7122, 5 }, { 7130, 68 }, { 7209, 3 }, { 7259, 68 }, { 7309, 1 }, { 7315, 3 }, { 7322, 68 }, { 7348, 68 }, { 7420, 68 }, { 7461, 68 }, { 7545, 68 }, { 7554, 3 }, { 7630, 68 }, { 7666, 68 },\n                { 7815, 1 }, { 7972, 1 }, { 7972, 68 }, { 7988, 68 }, { 8049, 8 }, { 8254, 68 }, { 8269, 68 }, { 8352, 1 }, { 8378, 68 }, { 8526, 68 }, { 8531, 68 }, { 8583, 68 }, { 8615, 68 }, { 8619, 3 }, { 8623, 68 }, { 8692, 1 }, { 8698, 68 }, { 8773, 68 }, { 8777, 3 }, { 8822, 68 }, { 8929, 68 }, { 8935, 68 }, { 9025, 68 }, { 9054, 68 },\n                { 9056, 1 }, { 9086, 68 }, { 9147, 3 }, { 9219, 68 }, { 9230, 3 }, { 9248, 68 }, { 9283, 68 }, { 9314, 68 }, { 9418, 1 }, { 9426, 68 }, { 9456, 1 }, { 9594, 68 }, { 9628, 68 }, { 9642, 68 }, { 9646, 68 }, { 9686, 1 }, { 9709, 68 }, { 9771, 3 }, { 9782, 68 }, { 9884, 68 }, { 9914, 5 }, { 10004, 4 }, { 10033, 6 }, { 10052, 68 },\n                { 10086, 68 }, { 10168, 68 }, { 10176, 1 }, { 10228, 68 }, { 10312, 68 }, { 10372, 68 }, { 10622, 68 }, { 10685, 68 }, { 10687, 1 }, { 10787, 68 }, { 11010, 68 }, { 11024, 68 }, { 11044, 68 }, { 11086, 68 }, { 11149, 1 }, { 11198, 68 }, { 11265, 68 }, { 11302, 68 }, { 11326, 68 }, { 11354, 68 }, { 11404, 1 }, { 11473, 68 },\n                { 11506, 68 }, { 11548, 4 }, { 11575, 68 }, { 11621, 4 }, { 11625, 3 }, { 11625, 1 }, { 11642, 4 }, { 11859, 5 }, { 11870, 68 }, { 11872, 3 }, { 11880, 7 }, { 11886, 3 }, { 11905, 6 }, { 11880, 3 }, { 11912, 6 }, { 11916, 4 }, { 11916, 3 }, { 11965, 4 }, { 12068, 13 }, { 12106, 68 }, { 12120, 68 }, { 12221, 68 }, { 12257, 68 },\n                { 12361, 68 }, { 12411, 68 }, { 12473, 3 }, { 12554, 68 }, { 12583, 68 }, { 12654, 68 }, { 12665, 68 }, { 12744, 1 }, { 12775, 68 }, { 12858, 68 }, { 12993, 68 }, { 13007, 3 }, { 13025, 4 }, { 13038, 68 }, { 13092, 4 }, { 13094, 5 }, { 13095, 1 }, { 13110, 68 }, { 13116, 1 }, { 13140, 68 }, { 13169, 1 }, { 13186, 68 },\n                { 13202, 68 }, { 13202, 1 }, { 13256, 68 }, { 13344, 68 }, { 13373, 68 }, { 13396, 3 }, { 13446, 68 }, { 13451, 3 }, { 13475, 68 }, { 13521, 1 }, { 13587, 68 }, { 13592, 68 }, { 13708, 3 }, { 13711, 1 }, { 13741, 1 }, { 13757, 1 }, { 13847, 68 }, { 13881, 3 }, { 13915, 1 }, { 14005, 68 }, { 14028, 68 }, { 14037, 68 },\n                { 14074, 68 }, { 14135, 68 }, { 14176, 68 }, { 14227, 68 }, { 14228, 68 }, { 14271, 3 }, { 14279, 3 }, { 14493, 68 }, { 14535, 3 }, { 14535, 1 }, { 14680, 68 }, { 14717, 68 }, { 14725, 1 }, { 14790, 68 }, { 14801, 1 }, { 14959, 68 }, { 15052, 68 }, { 15055, 1 }, { 15055, 1 }, { 15075, 68 }, { 15103, 8 }, { 15153, 16 },\n                { 15191, 68 }, { 15240, 68 }, { 15313, 68 }, { 15323, 68 }, { 15341, 1 }, { 15383, 68 }, { 15387, 68 }, { 15491, 68 }, { 15534, 68 }, { 15539, 68 }, { 15549, 68 }, { 15554, 1 }, { 15664, 1 }, { 15726, 68 }, { 15807, 68 }, { 15842, 68 }, { 15897, 68 }, { 15913, 3 }, { 15925, 68 }, { 15935, 68 }, { 16131, 1 }, { 16211, 3 },\n                { 16249, 68 }, { 16268, 68 }, { 16307, 68 }, { 16398, 68 }, { 16498, 68 }, { 16518, 1 }, { 16552, 1 }, { 16571, 68 }, { 16592, 68 }, { 16601, 3 }, { 16638, 68 }, { 16698, 68 }, { 16712, 1 }, { 16767, 68 }, { 16789, 68 }, { 16992, 68 }, { 17015, 68 }, { 17035, 68 }, { 17074, 3 }, { 17086, 3 }, { 17086, 1 }, { 17092, 1 },\n                { 17110, 4 }, { 17116, 3 }, { 17236, 68 }, { 17291, 68 }, { 17291, 68 }, { 17340, 68 }, { 17342, 1 }, { 17360, 3 }, { 17436, 3 }, { 17457, 68 }, { 17508, 1 }, { 17556, 68 }, { 17601, 68 }, { 17639, 68 }, { 17671, 68 }, { 17743, 68 }, { 17857, 68 }, { 17915, 68 }, { 17992, 68 }, { 18077, 1 }, { 18088, 68 }, { 18158, 1 },\n                { 18239, 16 }, { 18242, 68 }, { 18252, 3 }, { 18299, 1 }, { 18405, 68 }, { 18433, 68 }, { 18444, 68 }, { 18490, 68 }, { 18497, 68 }, { 18516, 68 }, { 18540, 68 }, { 18598, 68 }, { 18649, 68 }, { 18658, 68 }, { 18683, 68 }, { 18728, 68 }, { 18767, 1 }, { 18821, 68 }, { 18868, 68 }, { 18876, 68 }, { 18914, 14 }, { 19212, 1 },\n                { 19215, 1 }, { 19293, 68 }, { 19303, 68 }, { 19336, 68 }, { 19376, 68 }, { 19419, 68 }, { 19558, 68 }, { 19559, 1 }, { 19609, 68 }, { 19688, 68 }, { 19724, 68 }, { 19820, 1 }, { 19851, 68 }, { 19881, 68 }, { 19966, 68 }, { 19983, 3 }, { 19988, 4 }, { 20047, 1 }, { 20062, 68 }, { 20091, 1 }, { 20152, 1 }, { 20183, 1 },\n                { 20208, 68 }, { 20346, 68 }, { 20386, 1 }, { 20459, 68 }, { 20505, 68 }, { 20520, 1 }, { 20560, 3 }, { 20566, 3 }, { 20566, 1 }, { 20610, 68 }, { 20652, 68 }, { 20694, 68 }, { 20740, 68 }, { 20756, 68 }, { 20825, 3 }, { 20895, 68 }, { 20959, 1 }, { 20995, 68 }, { 21017, 3 }, { 21039, 68 }, { 21086, 1 }, { 21109, 3 }, { 21139, 3 },\n                { 21206, 68 }, { 21230, 68 }, { 21251, 3 }, { 21352, 68 }, { 21353, 68 }, { 21370, 3 }, { 21389, 1 }, { 21445, 3 }, { 21475, 68 }, { 21528, 68 }, { 21559, 3 }, { 21604, 68 }, { 21606, 1 }, { 21815, 68 }, { 21858, 3 }, { 21860, 3 }, { 22015, 68 }, { 22065, 68 }, { 22098, 5 }, { 22105, 68 }, { 22158, 3 }, { 22197, 68 }, { 22254, 1 },\n                { 22353, 68 }, { 22404, 4 }, { 22422, 68 }, { 22569, 68 }, { 22634, 68 }, { 22639, 68 }, { 22861, 68 }, { 22868, 68 }, { 22876, 1 }, { 22902, 68 }, { 22925, 68 }, { 23080, 68 }, { 23085, 3 }, { 23089, 5 }, { 23329, 1 }, { 23349, 68 }, { 23559, 5 }, { 23567, 3 }, { 23574, 68 }, { 23584, 3 }, { 23615, 3 }, { 23633, 68 },\n                { 23674, 68 }, { 23678, 1 }, { 23853, 68 }, { 23875, 68 }, { 24010, 4 }, { 24076, 68 }, { 24128, 6 }, { 24248, 68 }, { 24253, 68 }, { 24259, 1 }, { 24319, 68 }, { 24319, 1 }, { 24502, 3 }, { 24666, 68 }, { 24781, 3 }, { 24792, 68 }, { 24909, 68 }, { 24993, 68 }, { 25039, 1 }, { 25090, 3 }, { 25137, 1 }, { 25138, 3 }, { 25140, 3 },\n                { 25155, 5 }, { 25411, 68 }, { 25460, 68 }, { 25564, 3 }, { 25586, 3 }, { 25630, 68 }, { 25765, 68 }, { 25789, 3 }, { 25803, 68 }, { 25851, 68 }, { 25872, 68 }, { 25887, 68 }, { 25981, 1 }, { 26016, 68 }, { 26019, 1 }, { 26029, 1 }, { 26104, 7 }, { 26144, 68 }, { 26275, 1 }, { 26295, 68 }, { 26298, 1 }, { 26322, 68 },\n                { 26380, 68 }, { 26408, 4 }, { 26446, 1 }, { 26553, 1 }, { 26576, 1 }, { 26635, 1 }, { 26668, 68 }, { 26675, 68 }, { 26698, 4 }, { 26748, 9 }, { 26788, 68 }, { 26932, 68 }, { 26962, 68 }, { 27042, 68 }, { 27060, 68 }, { 27163, 3 }, { 27202, 68 }, { 27290, 68 }, { 27337, 3 }, { 27376, 68 }, { 27439, 68 }, { 27458, 4 },\n                { 27515, 68 }, { 27518, 1 }, { 27541, 68 }, { 27585, 3 }, { 27633, 68 }, { 27695, 68 }, { 27702, 68 }, { 27861, 68 }, { 27924, 1 }, { 28025, 14 }, { 28058, 68 }, { 28143, 68 }, { 28215, 68 }, { 28240, 68 }, { 28241, 68 }, { 28285, 68 }, { 28324, 3 }, { 28378, 68 }, { 28514, 68 }, { 28529, 68 }, { 28538, 68 }, { 28565, 3 },\n                { 28697, 68 }, { 28735, 68 }, { 28769, 68 }, { 28770, 4 }, { 28788, 4 }, { 28807, 3 }, { 28807, 4 }, { 28829, 1 }, { 28853, 68 }, { 28856, 7 }, { 28864, 68 }, { 28865, 3 }, { 28915, 68 }, { 28928, 68 }, { 28964, 68 }, { 28988, 1 }, { 29031, 68 }, { 29095, 68 }, { 29189, 68 }, { 29205, 1 }, { 29230, 1 }, { 29332, 68 },\n                { 29339, 68 }, { 29349, 5 }, { 29449, 68 }, { 29471, 68 }, { 29578, 68 }, { 29859, 68 }, { 29878, 68 }, { 29947, 10 }, { 30083, 68 }, { 30121, 68 }, { 30128, 68 }, { 30155, 4 }, { 30157, 1 }, { 30272, 68 }, { 30281, 68 }, { 30286, 68 }, { 30305, 68 }, { 30408, 68 }, { 30444, 268 }, { 30612, 68 }, { 30628, 68 }, { 30747, 68 },\n                { 30783, 68 }, { 30808, 5 }, { 30868, 3 }, { 30875, 68 }, { 30997, 68 }, { 31000, 68 }, { 31022, 3 }, { 31111, 1 }, { 31144, 68 }, { 31146, 3 }, { 31187, 68 }, { 31324, 68 }, { 31343, 68 }, { 31416, 68 }, { 31485, 68 }, { 31539, 68 }, { 31638, 68 }, { 31648, 68 }, { 31750, 68 }, { 31754, 68 }, { 31785, 10 }, { 31786, 5 },\n                { 31800, 68 }, { 31801, 4 }, { 31807, 7 }, { 31807, 3 }, { 31807, 10 }, { 31808, 3 }, { 31808, 4 }, { 31818, 6 }, { 31825, 7 }, { 31838, 68 }, { 31911, 1 }, { 31974, 68 }, { 32010, 3 }, { 32031, 68 }, { 32040, 68 }, { 32063, 1 }, { 32078, 68 }, { 32156, 68 }, { 32198, 31 }, { 32257, 68 }, { 32257, 68 }, { 32265, 68 },\n                { 32330, 68 }, { 32369, 8 }, { 32404, 3 }, { 32425, 68 }, { 32432, 68 }, { 32505, 68 }, { 32531, 68 }, { 32536, 68 }, { 32549, 68 }, { 32582, 3 }, { 32590, 4 }, { 32624, 68 }, { 32644, 68 }, { 32692, 68 }, { 32695, 4 }, { 32699, 3 }, { 32726, 4 }, { 32784, 68 }, { 32832, 68 }, { 32883, 6 }, { 32965, 4 }, { 33044, 68 },\n                { 33104, 68 }, { 33184, 68 }, { 33264, 1 }, { 33292, 68 }, { 33312, 1 }, { 33468, 68 }, { 33471, 1 }, { 33565, 68 }, { 33627, 68 }, { 33659, 68 }, { 33709, 68 }, { 33766, 5 }, { 33836, 68 }, { 33875, 68 }, { 33954, 68 }, { 33959, 68 }, { 34050, 68 }, { 34090, 68 }, { 34168, 68 }, { 34233, 68 }, { 34461, 68 }, { 34462, 1 },\n                { 34463, 68 }, { 34472, 4 }, { 34500, 68 }, { 34520, 68 }, { 34544, 68 }, { 34614, 68 }, { 34662, 1 }, { 34676, 68 }, { 34729, 4 }, { 34803, 68 }, { 34845, 68 }, { 34913, 68 }, { 34963, 6 }, { 35019, 68 }, { 35022, 68 }, { 35070, 68 }, { 35120, 68 }, { 35132, 68 }, { 35144, 68 }, { 35205, 68 }, { 35230, 3 }, { 35244, 68 },\n                { 35271, 4 }, { 35276, 68 }, { 35282, 68 }, { 35324, 3 }, { 35366, 3 }, { 35659, 68 }, { 35680, 68 }, { 35744, 68 }, { 35758, 3 }, { 35796, 68 }, { 35830, 68 }, { 35841, 7 }, { 35843, 68 }, { 35856, 68 }, { 35914, 4 }, { 35929, 13 }, { 35993, 68 }, { 35997, 1 }, { 36046, 4 }, { 36046, 1 }, { 36051, 1 }, { 36111, 68 }, { 36208, 1 },\n                { 36208, 1 }, { 36306, 68 }, { 36325, 68 }, { 36386, 68 }, { 36405, 68 }, { 36443, 1 }, { 36455, 1 }, { 36538, 68 }, { 36562, 68 }, { 36566, 68 }, { 36628, 68 }, { 36693, 68 }, { 36713, 68 }, { 36730, 68 }, { 36747, 68 }, { 36786, 68 }, { 36810, 1 }, { 36848, 68 }, { 36914, 1 }, { 36920, 68 }, { 36952, 68 }, { 37071, 68 },\n                { 37086, 1 }, { 37094, 3 }, { 37158, 3 }, { 37231, 68 }, { 37241, 68 }, { 37285, 68 }, { 37349, 68 }, { 37404, 68 }, { 37410, 1 }, { 37433, 4 }, { 37615, 68 }, { 37659, 68 }, { 37742, 68 }, { 37773, 68 }, { 37867, 1 }, { 37890, 68 }, { 37960, 68 }, { 38042, 3 }, { 38241, 68 }, { 38400, 68 }, { 38461, 1 }, { 38551, 68 },\n                { 38611, 1 }, { 38657, 68 }, { 38729, 68 }, { 38748, 68 }, { 38815, 68 }, { 38852, 68 }, { 38890, 1 }, { 38954, 68 }, { 39119, 68 }, { 39162, 68 }, { 39175, 3 }, { 39176, 68 }, { 39231, 68 }, { 39261, 68 }, { 39467, 68 }, { 39500, 68 }, { 39507, 68 }, { 39566, 68 }, { 39608, 68 }, { 39686, 6 }, { 39730, 68 }, { 39842, 1 },\n                { 39853, 1 }, { 39905, 68 }, { 39931, 68 }, { 39989, 68 }, { 40030, 68 }, { 40227, 68 }, { 40268, 68 }, { 40372, 68 }, { 40415, 1 }, { 40488, 3 }, { 40536, 68 }, { 40676, 3 }, { 40677, 68 }, { 40755, 68 }, { 40842, 68 }, { 40849, 1 }, { 40870, 3 }, { 40873, 3 }, { 40972, 68 }, { 41033, 68 }, { 41190, 68 }, { 41273, 5 },\n                { 41273, 1 }, { 41293, 68 }, { 41367, 368 }, { 41376, 68 }, { 41420, 68 }, { 41473, 68 }, { 41473, 68 }, { 41493, 4 }, { 41521, 68 }, { 41533, 68 }, { 41554, 68 }, { 41568, 68 }, { 41583, 3 }, { 41728, 68 }, { 41786, 68 }, { 41836, 1 }, { 41875, 68 }, { 41933, 68 }, { 42044, 68 }, { 42075, 68 }, { 42076, 68 }, { 42133, 68 },\n                { 42259, 29 }, { 42269, 3 }, { 42294, 68 }, { 42420, 68 }, { 42524, 68 }, { 42524, 1 }, { 42546, 1 }, { 42631, 68 }, { 42693, 68 }, { 42740, 68 }, { 42744, 4 }, { 42755, 1 }, { 42870, 68 }, { 42894, 68 }, { 42939, 68 }, { 42973, 68 }, { 43016, 68 }, { 43070, 68 }, { 43105, 68 }, { 43115, 68 }, { 43375, 3 }, { 43387, 1 },\n                { 43424, 3 }, { 43448, 68 }, { 43480, 68 }, { 43498, 68 }, { 43651, 68 }, { 43727, 68 }, { 43879, 68 }, { 43910, 1 }, { 43977, 68 }, { 44003, 68 }, { 44080, 68 }, { 44082, 1 }, { 44136, 68 }, { 44169, 29 }, { 44186, 68 }, { 44339, 68 }, { 44350, 1 }, { 44356, 1 }, { 44430, 68 }, { 44440, 1 }, { 44530, 1 }, { 44538, 68 },\n                { 44572, 68 }, { 44585, 68 }, { 44709, 68 }, { 44748, 68 }, { 44748, 68 }, { 44769, 68 }, { 44813, 68 }, { 44890, 68 }, { 45015, 68 }, { 45046, 4 }, { 45052, 68 }, { 45062, 68 }, { 45094, 6 }, { 45184, 68 }, { 45191, 68 }, { 45201, 3 }, { 45216, 3 }, { 45227, 68 }, { 45269, 1 }, { 45294, 68 }, { 45314, 68 }, { 45345, 8 },\n                { 45352, 68 }, { 45365, 3 }, { 45378, 1 }, { 45392, 4 }, { 45405, 3 }, { 45410, 68 }, { 45448, 14 }, { 45450, 68 }, { 45457, 68 }, { 45466, 3 }, { 45481, 4 }, { 45486, 7 }, { 45533, 5 }, { 45576, 68 }, { 45649, 68 }, { 45917, 68 }, { 45919, 6 }, { 45919, 1 }, { 45930, 15 }, { 45930, 68 }, { 46001, 5 }, { 46036, 68 }, { 46054, 68 },\n                { 46075, 68 }, { 46153, 68 }, { 46155, 68 }, { 46228, 68 }, { 46234, 68 }, { 46273, 68 }, { 46387, 68 }, { 46398, 68 }, { 46517, 68 }, { 46559, 68 }, { 46565, 1 }, { 46598, 68 }, { 46686, 68 }, { 46744, 68 }, { 46816, 3 }, { 46835, 68 }, { 46921, 68 }, { 46938, 68 }, { 46991, 68 }, { 47038, 68 }, { 47098, 3 }, { 47107, 68 },\n                { 47201, 3 }, { 47327, 1 }, { 47327, 1 }, { 47338, 68 }, { 47395, 1 }, { 47499, 68 }, { 47504, 68 }, { 47515, 1 }, { 47516, 1 }, { 47600, 1 }, { 47604, 1 }, { 47707, 1 }, { 47728, 1 }, { 47748, 68 }, { 47763, 68 }, { 47807, 4 }, { 47814, 68 }, { 47822, 68 }, { 47834, 68 }, { 47843, 3 }, { 47886, 68 }, { 47893, 68 }, { 48066, 68 },\n                { 48126, 68 }, { 48133, 1 }, { 48166, 68 }, { 48299, 1 }, { 48455, 68 }, { 48468, 68 }, { 48568, 68 }, { 48606, 68 }, { 48642, 68 }, { 48698, 68 }, { 48714, 68 }, { 48754, 68 }, { 48765, 3 }, { 48773, 5 }, { 48819, 68 }, { 48833, 68 }, { 48904, 68 }, { 49000, 1 }, { 49113, 168 }, { 49140, 68 }, { 49276, 68 }, { 49353, 68 },\n                { 49411, 3 }, { 49418, 68 }, { 49540, 68 }, { 49544, 68 }, { 49584, 68 }, { 49602, 68 }, { 49784, 5 }, { 49822, 4 }, { 49822, 5 }, { 49828, 68 }, { 49866, 68 }, { 49922, 3 }, { 49959, 68 }, { 50045, 68 }, { 50134, 3 }, { 50140, 68 }, { 50237, 68 }, { 50247, 68 }, { 50266, 13 }, { 50290, 68 }, { 50312, 4 }, { 50314, 1 },\n                { 50527, 68 }, { 50605, 1 }, { 50730, 68 }, { 50751, 68 }, { 50770, 68 }, { 50858, 68 }, { 50859, 68 }, { 50909, 68 }, { 50948, 3 }, { 51043, 68 }, { 51048, 68 }, { 51089, 68 }, { 51090, 68 }, { 51141, 68 }, { 51163, 68 }, { 51250, 68 }, { 51347, 68 }, { 51475, 68 }, { 51536, 68 }, { 51544, 68 }, { 51595, 68 }, { 51602, 19 },\n                { 51643, 5 }, { 51702, 68 }, { 51702, 10 }, { 51764, 68 }, { 51793, 5 }, { 51812, 68 }, { 51839, 1 }, { 51938, 3 }, { 51941, 1 }, { 51967, 4 }, { 52049, 3 }, { 52074, 3 }, { 52098, 68 }, { 52118, 68 }, { 52119, 3 }, { 52227, 11 }, { 52246, 3 }, { 52282, 68 }, { 52451, 68 }, { 52583, 68 }, { 52601, 1 }, { 52605, 68 }, { 52615, 68 },\n                { 52668, 68 }, { 52824, 68 }, { 53076, 1 }, { 53120, 1 }, { 53179, 68 }, { 53189, 68 }, { 53193, 1 }, { 53195, 68 }, { 53246, 68 }, { 53249, 68 }, { 53268, 1 }, { 53295, 68 }, { 53312, 68 }, { 53410, 68 }, { 53451, 68 }, { 53570, 68 }, { 53593, 68 }, { 53635, 68 }, { 53657, 68 }, { 53682, 3 }, { 53728, 5 }, { 53733, 68 },\n                { 53753, 68 }, { 53787, 4 }, { 53807, 1 }, { 54008, 68 }, { 54059, 68 }, { 54060, 1 }, { 54080, 68 }, { 54090, 1 }, { 54138, 68 }, { 54149, 68 }, { 54168, 1 }, { 54171, 68 }, { 54216, 268 }, { 54233, 6 }, { 54434, 68 }, { 54534, 68 }, { 54562, 68 }, { 54763, 68 }, { 54791, 68 }, { 54816, 68 }, { 54909, 68 }, { 54916, 3 },\n                { 54963, 68 }, { 54985, 68 }, { 54991, 3 }, { 55016, 3 }, { 55025, 3 }, { 55032, 68 }, { 55099, 68 }, { 55260, 68 }, { 55261, 68 }, { 55270, 3 }, { 55384, 68 }, { 55455, 68 }, { 55456, 68 }, { 55504, 3 }, { 55510, 68 }, { 55558, 68 }, { 55568, 68 }, { 55585, 68 }, { 55677, 68 }, { 55703, 68 }, { 55749, 68 }, { 55779, 68 },\n                { 55789, 3 }, { 55792, 68 }, { 55830, 4 }, { 55835, 68 }, { 55879, 68 }, { 56076, 68 }, { 56118, 68 }, { 56314, 68 }, { 56392, 1 }, { 56411, 68 }, { 56459, 68 }, { 56553, 34 }, { 56575, 68 }, { 56733, 68 }, { 56762, 68 }, { 56793, 3 }, { 56877, 3 }, { 56927, 68 }, { 56981, 68 }, { 57014, 1 }, { 57149, 68 }, { 57162, 68 },\n                { 57186, 68 }, { 57254, 68 }, { 57267, 1 }, { 57324, 68 }, { 57327, 68 }, { 57365, 4 }, { 57371, 68 }, { 57445, 68 }, { 57477, 68 }, { 57497, 68 }, { 57536, 68 }, { 57609, 68 }, { 57626, 68 }, { 57666, 68 }, { 57694, 68 }, { 57694, 68 }, { 57749, 68 }, { 57781, 7 }, { 57878, 68 }, { 57953, 68 }, { 58051, 68 }, { 58088, 68 },\n                { 58097, 68 }, { 58142, 3 }, { 58142, 1 }, { 58197, 1 }, { 58221, 68 }, { 58222, 68 }, { 58244, 68 }, { 58290, 1 }, { 58296, 1 }, { 58325, 68 }, { 58378, 1 }, { 58389, 3 }, { 58430, 68 }, { 58454, 68 }, { 58551, 29 }, { 58563, 6 }, { 58681, 68 }, { 58751, 8 }, { 58752, 43 }, { 58790, 5 }, { 58846, 68 }, { 58879, 6 }, { 58953, 68 },\n                { 58998, 68 }, { 59010, 1 }, { 59038, 5 }, { 59135, 68 }, { 59166, 68 }, { 59180, 68 }, { 59222, 68 }, { 59227, 68 }, { 59307, 68 }, { 59398, 3 }, { 59411, 68 }, { 59436, 3 }, { 59464, 68 }, { 59569, 68 }, { 59587, 68 }, { 59624, 3 }, { 59786, 68 }, { 59834, 68 }, { 59841, 68 }, { 59841, 1 }, { 59984, 68 }, { 59985, 68 },\n                { 60003, 3 }, { 60045, 68 }, { 60097, 68 }, { 60148, 68 }, { 60172, 68 }, { 60203, 5 }, { 60565, 68 }, { 60625, 68 }, { 60743, 68 }, { 60781, 68 }, { 60892, 68 }, { 60977, 68 }, { 60979, 68 }, { 61021, 5 }, { 61021, 4 }, { 61026, 68 }, { 61139, 68 }, { 61165, 3 }, { 61204, 68 }, { 61207, 1 }, { 61248, 3 }, { 61257, 68 },\n                { 61264, 6 }, { 61272, 3 }, { 61410, 68 }, { 61410, 3 }, { 61416, 68 }, { 61423, 1 }, { 61503, 68 }, { 61503, 68 }, { 61533, 68 }, { 61567, 68 }, { 61575, 68 }, { 61835, 1 }, { 61842, 1 }, { 61924, 68 }, { 61951, 6 }, { 61975, 68 }, { 61986, 3 }, { 62024, 1 }, { 62110, 68 }, { 62135, 68 }, { 62192, 68 }, { 62208, 68 },\n                { 62399, 68 }, { 62400, 1 }, { 62414, 68 }, { 62423, 3 }, { 62456, 3 }, { 62459, 3 }, { 62478, 3 }, { 62484, 68 }, { 62510, 6 }, { 62511, 3 }, { 62565, 3 }, { 62610, 68 }, { 62875, 4 }, { 62896, 5 }, { 62898, 68 }, { 62904, 68 }, { 62938, 3 }, { 62943, 68 }, { 62977, 68 }, { 62989, 3 }, { 62998, 5 }, { 63069, 1 }, { 63093, 5 },\n                { 63107, 68 }, { 63113, 1 }, { 63231, 4 }, { 63253, 68 }, { 63286, 4 }, { 63289, 68 }, { 63334, 1 }, { 63334, 4 }, { 63413, 68 }, { 63425, 68 }, { 63512, 10 }, { 63537, 1 }, { 63694, 1 }, { 63721, 4 }, { 63749, 68 }, { 63783, 17 }, { 63791, 3 }, { 63792, 68 }, { 63882, 25 }, { 63896, 1 }, { 63936, 68 }, { 63969, 3 }, { 63986, 68 },\n                { 63988, 68 }, { 64009, 10 }, { 64018, 68 }, { 64032, 6 }, { 64125, 68 }, { 64195, 1 }, { 64221, 7 }, { 64390, 68 }, { 64459, 68 }, { 64568, 68 }, { 64784, 1 }, { 64789, 68 }, { 64829, 68 }, { 64848, 1 }, { 64914, 68 }, { 64928, 1 }, { 64939, 68 }, { 65026, 68 }, { 65057, 68 }, { 65070, 68 }, { 65193, 4 }, { 65235, 3 },\n                { 65242, 68 }, { 65281, 68 }, { 65320, 68 }, { 65365, 1 }, { 65414, 68 }, { 65445, 68 }, { 65581, 68 }, { 65624, 1 }, { 65719, 68 }, { 65766, 68 }, { 65927, 68 }, { 66004, 1 }, { 66031, 68 }, { 66085, 1 }, { 66085, 68 }, { 66133, 68 }, { 66134, 68 }, { 66188, 1 }, { 66240, 68 }, { 66249, 68 }, { 66250, 68 }, { 66295, 68 },\n                { 66342, 1 }, { 66352, 3 }, { 66388, 3 }, { 66432, 68 }, { 66437, 47 }, { 66497, 68 }, { 66517, 68 }, { 66526, 68 }, { 66546, 9 }, { 66605, 68 }, { 66753, 68 }, { 66792, 68 }, { 66796, 68 }, { 66828, 68 }, { 66899, 3 }, { 66970, 6 }, { 66981, 68 }, { 66983, 1 }, { 67009, 68 }, { 67017, 4 }, { 67115, 68 }, { 67117, 1 },\n                { 67130, 6 }, { 67132, 7 }, { 67162, 68 }, { 67179, 6 }, { 67236, 68 }, { 67263, 3 }, { 67274, 68 }, { 67274, 68 }, { 67349, 3 }, { 67486, 68 }, { 67503, 3 }, { 67517, 1 }, { 67559, 1 }, { 67660, 68 }, { 67727, 68 }, { 67901, 68 }, { 67943, 4 }, { 67950, 68 }, { 67965, 3 }, { 68029, 68 }, { 68048, 68 }, { 68169, 68 }, { 68172, 1 },\n                { 68258, 68 }, { 68288, 1 }, { 68359, 68 }, { 68441, 68 }, { 68484, 68 }, { 68488, 68 }, { 68525, 68 }, { 68535, 68 }, { 68575, 7 }, { 68575, 5 }, { 68583, 68 }, { 68588, 4 }, { 68593, 1 }, { 68597, 68 }, { 68636, 68 }, { 68636, 68 }, { 68667, 68 }, { 68785, 1 }, { 68914, 4 }, { 68915, 5 }, { 68940, 3 }, { 69010, 68 },\n                { 69063, 68 }, { 69076, 68 }, { 69235, 68 }, { 69270, 68 }, { 69298, 1 }, { 69350, 5 }, { 69432, 68 }, { 69514, 68 }, { 69562, 3 }, { 69562, 4 }, { 69638, 1 }, { 69656, 68 }, { 69709, 68 }, { 69775, 68 }, { 69788, 68 }, { 70193, 68 }, { 70233, 68 }, { 70252, 68 }, { 70259, 68 }, { 70293, 3 }, { 70405, 3 }, { 70462, 68 },\n                { 70515, 3 }, { 70518, 68 }, { 70535, 6 }, { 70547, 6 }, { 70577, 6 }, { 70631, 17 }, { 70667, 68 }, { 70680, 1 }, { 70694, 1 }, { 70898, 68 }, { 70916, 1 }, { 70936, 3 }, { 71033, 68 }, { 71126, 68 }, { 71158, 68 }, { 71162, 68 }, { 71421, 1 }, { 71441, 68 }, { 71557, 68 }, { 71789, 1 }, { 71816, 68 }, { 71850, 1 }, { 71869, 1 },\n                { 71961, 68 }, { 71973, 4 }, { 72064, 68 }, { 72110, 68 }, { 72117, 3 }, { 72164, 68 }, { 72266, 68 }, { 72325, 68 }, { 72326, 1 }, { 72420, 68 }, { 72693, 68 }, { 72705, 1 }, { 72730, 68 }, { 72793, 68 }, { 72795, 1 }, { 72939, 1 }, { 72945, 3 }, { 72945, 68 }, { 73120, 1 }, { 73121, 5 }, { 73122, 4 }, { 73126, 1 }, { 73126, 1 },\n                { 73196, 3 }, { 73219, 68 }, { 73241, 6 }, { 73272, 3 }, { 73354, 1 }, { 73368, 68 }, { 73467, 1 }, { 73517, 68 }, { 73554, 68 }, { 73678, 68 }, { 73838, 1 }, { 73881, 68 }, { 73958, 68 }, { 73985, 15 }, { 74092, 68 }, { 74205, 68 }, { 74245, 68 }, { 74277, 68 }, { 74286, 68 }, { 74353, 68 }, { 74403, 68 }, { 74428, 1 },\n                { 74468, 68 }, { 74481, 3 }, { 74511, 68 }, { 74537, 68 }, { 74596, 68 }, { 74750, 68 }, { 74754, 68 }, { 74861, 68 }, { 74933, 4 }, { 74970, 1 }, { 75003, 3 }, { 75077, 1 }, { 75159, 68 }, { 75170, 68 }, { 75234, 45 }, { 75300, 3 }, { 75337, 68 }, { 75345, 68 }, { 75419, 1 }, { 75429, 68 }, { 75477, 1 }, { 75513, 68 },\n                { 75536, 68 }, { 75536, 68 }, { 75539, 1 }, { 75551, 68 }, { 75561, 68 }, { 75565, 68 }, { 75590, 68 }, { 75623, 5 }, { 75773, 6 }, { 75777, 6 }, { 75785, 68 }, { 75791, 68 }, { 75804, 68 }, { 75862, 68 }, { 75924, 3 }, { 75927, 68 }, { 75996, 11 }, { 76000, 1 }, { 76006, 68 }, { 76020, 3 }, { 76110, 68 }, { 76126, 3 },\n                { 76131, 68 }, { 76136, 68 }, { 76144, 68 }, { 76203, 68 }, { 76229, 3 }, { 76244, 15 }, { 76246, 68 }, { 76300, 1 }, { 76403, 3 }, { 76545, 68 }, { 76569, 68 }, { 76813, 68 }, { 76821, 68 }, { 76837, 68 }, { 76863, 68 }, { 77027, 68 }, { 77037, 65 }, { 77074, 3 }, { 77170, 68 }, { 77191, 68 }, { 77220, 68 }, { 77230, 68 },\n                { 77261, 68 }, { 77277, 68 }, { 77309, 68 }, { 77314, 68 }, { 77412, 68 }, { 77419, 68 }, { 77457, 68 }, { 77633, 3 }, { 77714, 68 }, { 77855, 68 }, { 77857, 1 }, { 77876, 68 }, { 77895, 68 }, { 77916, 5 }, { 77947, 68 }, { 77948, 1 }, { 77966, 1 }, { 77996, 68 }, { 78025, 1 }, { 78064, 68 }, { 78100, 68 }, { 78113, 1 },\n                { 78114, 3 }, { 78167, 68 }, { 78175, 68 }, { 78260, 68 }, { 78261, 1 }, { 78265, 68 }, { 78286, 1 }, { 78300, 68 }, { 78327, 3 }, { 78363, 1 }, { 78384, 68 }, { 78459, 68 }, { 78516, 68 }, { 78612, 68 }, { 78643, 68 }, { 78655, 68 }, { 78698, 1 }, { 78720, 3 }, { 78789, 76 }, { 78838, 5 }, { 78893, 1 }, { 78954, 7 },\n                { 79007, 68 }, { 79132, 3 }, { 79193, 68 }, { 79193, 68 }, { 79226, 68 }, { 79411, 68 }, { 79422, 1 }, { 79502, 68 }, { 79593, 68 }, { 79622, 68 }, { 79657, 3 }, { 79771, 68 }, { 79866, 68 }, { 79909, 68 }, { 80005, 68 }, { 80032, 68 }, { 80060, 1 }, { 80132, 68 }, { 80149, 3 }, { 80251, 68 }, { 80363, 68 }, { 80379, 1 },\n                { 80464, 68 }, { 80498, 68 }, { 80553, 68 }, { 80556, 3 }, { 80559, 1 }, { 80571, 68 }, { 80652, 1 }, { 80703, 68 }, { 80754, 68 }, { 80754, 68 }, { 80860, 68 }, { 81055, 68 }, { 81087, 4 }, { 81210, 68 }, { 81211, 1 }, { 81216, 1 }, { 81223, 1 }, { 81231, 1 }, { 81288, 68 }, { 81317, 68 }, { 81327, 65 }, { 81332, 68 },\n                { 81376, 68 }, { 81469, 68 }, { 81579, 68 }, { 81617, 1 }, { 81630, 68 }, { 81666, 68 }, { 81800, 68 }, { 81832, 68 }, { 81848, 68 }, { 81869, 68 }, { 81941, 3 }, { 82177, 3 }, { 82179, 68 }, { 82180, 68 }, { 82182, 4 }, { 82185, 68 }, { 82195, 68 }, { 82238, 4 }, { 82265, 3 }, { 82295, 10 }, { 82299, 9 }, { 82367, 3 },\n                { 82379, 3 }, { 82380, 1 }, { 82505, 68 }, { 82568, 68 }, { 82620, 1 }, { 82637, 5 }, { 82821, 68 }, { 82841, 68 }, { 82945, 1 }, { 83020, 168 }, { 83072, 68 }, { 83181, 68 }, { 83240, 68 }, { 83253, 3 }, { 83261, 68 }, { 83288, 68 }, { 83291, 4 }, { 83295, 3 }, { 83365, 68 }, { 83368, 68 }, { 83408, 68 }, { 83458, 68 },\n                { 83470, 68 }, { 83471, 1 }, { 83637, 3 }, { 83693, 68 }, { 83703, 68 }, { 83732, 68 }, { 83745, 1 }, { 83800, 4 }, { 83801, 3 }, { 83856, 3 }, { 83863, 5 }, { 83867, 68 }, { 83868, 3 }, { 83898, 7 }, { 83900, 4 }, { 83901, 5 }, { 83989, 68 }, { 84049, 35 }, { 84086, 68 }, { 84089, 68 }, { 84115, 3 }, { 84130, 3 }, { 84132, 68 },\n                { 84143, 54 }, { 84173, 68 }, { 84185, 5 }, { 84297, 68 }, { 84390, 68 }, { 84497, 4 }, { 84657, 68 }, { 84657, 68 }, { 84724, 68 }, { 84775, 68 }, { 84870, 68 }, { 84892, 68 }, { 84910, 3 }, { 84935, 3 }, { 85002, 68 }, { 85051, 68 }, { 85052, 68 }, { 85135, 25 }, { 85135, 68 }, { 85144, 68 }, { 85165, 3 }, { 85205, 68 },\n                { 85232, 68 }, { 85281, 5 }, { 85423, 6 }, { 85539, 68 }, { 85582, 4 }, { 85609, 68 }, { 85701, 36 }, { 85705, 68 }, { 85824, 68 }, { 85824, 68 }, { 85858, 30 }, { 85858, 28 }, { 85904, 35 }, { 85910, 68 }, { 85913, 68 }, { 85926, 3 }, { 85942, 4 }, { 85969, 4 }, { 85996, 1 }, { 86013, 3 }, { 86034, 13 }, { 86068, 8 },\n                { 86069, 8 }, { 86089, 8 }, { 86193, 13 }, { 86217, 7 }, { 86219, 68 }, { 86250, 68 }, { 86304, 16 }, { 86317, 68 }, { 86322, 4 }, { 86325, 68 }, { 86333, 68 }, { 86394, 68 }, { 86433, 68 }, { 86469, 3 }, { 86512, 4 }, { 86537, 68 }, { 86627, 68 }, { 86658, 68 }, { 86810, 68 }, { 86813, 68 }, { 86884, 68 }, { 86947, 68 },\n                { 87003, 68 }, { 87010, 5 }, { 87019, 68 }, { 87027, 68 }, { 87105, 68 }, { 87107, 68 }, { 87183, 68 }, { 87273, 68 }, { 87358, 3 }, { 87388, 3 }, { 87503, 4 }, { 87639, 68 }, { 87649, 4 }, { 87722, 68 }, { 87829, 68 }, { 87829, 1 }, { 87863, 68 }, { 87894, 68 }, { 87988, 368 }, { 88035, 27 }, { 88059, 3 }, { 88094, 5 },\n                { 88111, 21 }, { 88129, 68 }, { 88175, 5 }, { 88256, 68 }, { 88329, 76 }, { 88415, 3 }, { 88482, 68 }, { 88502, 1 }, { 88529, 68 }, { 88551, 3 }, { 88552, 1 }, { 88713, 68 }, { 88797, 68 }, { 88844, 27 }, { 88925, 5 }, { 88935, 68 }, { 88944, 1 }, { 89073, 68 }, { 89095, 3 }, { 89283, 68 }, { 89294, 3 }, { 89299, 68 },\n                { 89324, 68 }, { 89368, 68 }, { 89387, 68 }, { 89464, 68 }, { 89607, 68 }, { 89737, 68 }, { 89791, 68 }, { 89794, 3 }, { 89840, 68 }, { 89849, 3 }, { 89859, 68 }, { 89905, 68 }, { 89952, 38 }, { 90030, 7 }, { 90030, 6 }, { 90031, 1 }, { 90072, 68 }, { 90090, 68 }, { 90146, 3 }, { 90202, 23 }, { 90302, 3 }, { 90328, 14 },\n                { 90335, 14 }, { 90338, 8 }, { 90380, 68 }, { 90434, 1 }, { 90482, 68 }, { 90527, 9 }, { 90537, 68 }, { 90545, 68 }, { 90639, 5 }, { 90642, 68 }, { 90709, 68 }, { 90775, 1 }, { 90806, 68 }, { 90845, 19 }, { 90872, 4 }, { 90884, 68 }, { 90910, 68 }, { 90994, 5 }, { 91046, 8 }, { 91059, 8 }, { 91096, 39 }, { 91147, 68 },\n                { 91168, 1 }, { 91493, 68 }, { 91513, 3 }, { 91618, 3 }, { 91653, 68 }, { 91817, 68 }, { 91831, 3 }, { 91833, 3 }, { 91885, 68 }, { 91919, 68 }, { 91934, 68 }, { 92245, 1 }, { 92284, 68 }, { 92292, 4 }, { 92369, 3 }, { 92388, 68 }, { 92426, 7 }, { 92720, 14 }, { 92720, 6 }, { 92729, 9 }, { 92733, 13 }, { 92735, 6 }, { 92786, 68 },\n                { 92853, 31 }, { 92906, 68 }, { 93031, 7 }, { 93077, 68 }, { 93102, 68 }, { 93109, 68 }, { 93122, 3 }, { 93214, 68 }, { 93330, 68 }, { 93395, 68 }, { 93506, 68 }, { 93564, 9 }, { 93713, 9 }, { 93722, 4 }, { 93840, 68 }, { 93877, 4 }, { 93891, 3 }, { 93948, 68 }, { 93981, 68 }, { 94012, 3 }, { 94033, 68 }, { 94121, 68 },\n                { 94165, 368 }, { 94181, 3 }, { 94210, 68 }, { 94216, 68 }, { 94230, 68 }, { 94333, 31 }, { 94433, 3 }, { 94497, 3 }, { 94609, 68 }, { 94623, 68 }, { 94763, 68 }, { 94780, 68 }, { 95287, 68 }, { 95348, 68 }, { 95433, 5 }, { 95446, 68 }, { 95493, 7 }, { 95517, 3 }, { 95580, 68 }, { 95610, 5 }, { 95620, 68 }, { 95678, 3 },\n                { 95683, 68 }, { 95689, 68 }, { 95760, 68 }, { 95792, 68 }, { 95850, 68 }, { 95908, 68 }, { 95908, 68 }, { 95967, 68 }, { 96022, 3 }, { 96088, 65 }, { 96460, 68 }, { 96554, 68 }, { 96597, 68 }, { 96763, 68 }, { 96808, 68 }, { 96854, 1 }, { 96963, 1 }, { 97007, 3 }, { 97125, 1 }, { 97128, 68 }, { 97133, 3 }, { 97142, 3 },\n                { 97156, 68 }, { 97223, 68 }, { 97244, 68 }, { 97303, 68 }, { 97355, 68 }, { 97356, 3 }, { 97393, 3 }, { 97409, 1 }, { 97451, 68 }, { 97539, 68 }, { 97546, 68 }, { 97553, 68 }, { 97627, 68 }, { 97640, 68 }, { 97650, 6 }, { 97675, 68 }, { 97685, 3 }, { 97773, 68 }, { 97802, 4 }, { 97826, 19 }, { 97860, 68 }, { 97956, 68 },\n                { 97958, 68 }, { 97973, 3 }, { 97982, 68 }, { 98039, 68 }, { 98051, 68 }, { 98059, 68 }, { 98088, 68 }, { 98092, 4 }, { 98147, 68 }, { 98147, 68 }, { 98169, 68 }, { 98207, 65 }, { 98277, 1 }, { 98277, 268 }, { 98285, 68 }, { 98324, 3 }, { 98324, 3 }, { 98381, 31 }, { 98390, 68 }, { 98404, 68 }, { 98415, 4 }, { 98460, 68 },\n                { 98462, 1 }, { 98475, 3 }, { 98485, 68 }, { 98640, 1 }, { 98798, 68 }, { 98800, 4 }, { 98821, 68 }, { 98895, 68 }, { 98936, 68 }, { 98950, 68 }, { 98980, 68 }, { 99033, 68 }, { 99045, 68 }, { 99135, 68 }, { 99315, 30 }, { 99324, 68 }, { 99346, 68 }, { 99418, 68 }, { 99505, 68 }, { 99557, 68 }, { 99559, 68 }, { 99586, 68 },\n                { 99622, 68 }, { 99770, 1 }, { 99790, 68 }, { 99810, 68 }, { 99871, 1 }, { 99926, 68 }, { 99927, 68 }, { 99978, 68 }, { 99980, 68 }, { 100022, 3 }, { 100024, 1 }, { 100069, 68 }, { 100150, 68 }, { 100225, 63 }, { 100246, 1 }, { 100310, 68 }, { 100361, 68 }, { 100428, 1 }, { 100434, 68 }, { 100450, 4 }, { 100546, 68 },\n                { 100551, 68 }, { 100551, 68 }, { 100554, 1 }, { 100597, 68 }, { 100676, 68 }, { 100693, 68 }, { 100827, 68 }, { 100928, 68 }, { 100928, 1 }, { 100935, 68 }, { 100937, 3 }, { 101034, 68 }, { 101041, 68 }, { 101154, 68 }, { 101200, 4 }, { 101250, 68 }, { 101352, 68 }, { 101403, 68 }, { 101430, 1 }, { 101508, 3 }, { 101509, 3 },\n                { 101523, 10 }, { 101604, 68 }, { 101637, 68 }, { 101681, 4 }, { 101759, 1 }, { 101773, 1 }, { 101836, 1 }, { 101882, 4 }, { 101895, 68 }, { 101897, 68 }, { 101939, 68 }, { 101951, 6 }, { 101956, 5 }, { 102055, 1 }, { 102085, 68 }, { 102093, 67 }, { 102209, 68 }, { 102258, 6 }, { 102271, 68 }, { 102284, 68 }, { 102332, 68 },\n                { 102354, 68 }, { 102366, 68 }, { 102424, 3 }, { 102456, 68 }, { 102496, 1 }, { 102497, 3 }, { 102519, 3 }, { 102554, 1 }, { 102610, 5 }, { 102657, 68 }, { 102661, 4 }, { 102695, 4 }, { 102707, 168 }, { 102910, 68 }, { 102930, 5 }, { 102937, 9 }, { 102938, 7 }, { 102965, 6 }, { 102969, 7 }, { 103031, 68 }, { 103062, 68 },\n                { 103096, 68 }, { 103146, 68 }, { 103159, 68 }, { 103223, 68 }, { 103267, 68 }, { 103296, 68 }, { 103303, 68 }, { 103487, 68 }, { 103491, 68 }, { 103599, 68 }, { 103677, 68 }, { 103903, 1 }, { 104040, 68 }, { 104047, 1 }, { 104052, 68 }, { 104057, 4 }, { 104057, 68 }, { 104062, 98 }, { 104091, 68 }, { 104189, 3 }, { 104283, 8 },\n                { 104288, 4 }, { 104305, 3 }, { 104445, 68 }, { 104472, 68 }, { 104475, 1 }, { 104497, 4 }, { 104548, 68 }, { 104582, 68 }, { 104626, 1 }, { 104716, 68 }, { 104826, 68 }, { 104849, 68 }, { 104872, 1 }, { 104945, 1 }, { 104948, 68 }, { 105066, 68 }, { 105071, 1 }, { 105198, 4 }, { 105198, 4 }, { 105203, 68 }, { 105256, 6 },\n                { 105263, 68 }, { 105329, 68 }, { 105515, 68 }, { 105566, 68 }, { 105566, 68 }, { 105585, 68 }, { 105678, 68 }, { 105852, 68 }, { 105877, 68 }, { 105911, 68 }, { 106022, 1 }, { 106033, 68 }, { 106080, 68 }, { 106192, 68 }, { 106220, 3 }, { 106243, 68 }, { 106323, 11 }, { 106371, 68 }, { 106608, 68 }, { 106624, 87 }, { 106680, 3 },\n                { 106688, 1 }, { 106800, 1 }, { 106800, 1 }, { 106821, 4 }, { 106853, 1 }, { 106930, 3 }, { 106937, 68 }, { 106955, 68 }, { 106996, 68 }, { 106996, 1 }, { 107148, 4 }, { 107213, 16 }, { 107213, 68 }, { 107243, 68 }, { 107360, 68 }, { 107408, 68 }, { 107509, 4 }, { 107572, 68 }, { 107592, 68 }, { 107644, 5 }, { 107679, 68 },\n                { 107705, 3 }, { 107761, 4 }, { 107780, 68 }, { 107825, 68 }, { 108007, 68 }, { 108041, 4 }, { 108058, 68 }, { 108071, 1 }, { 108132, 68 }, { 108164, 68 }, { 108189, 68 }, { 108210, 68 }, { 108330, 68 }, { 108430, 68 }, { 108450, 68 }, { 108469, 68 }, { 108484, 68 }, { 108533, 68 }, { 108588, 68 }, { 108594, 68 }, { 108690, 68 },\n                { 108785, 76 }, { 108814, 68 }, { 108818, 1 }, { 108820, 68 }, { 108889, 68 }, { 108951, 68 }, { 108959, 68 }, { 108963, 68 }, { 109034, 68 }, { 109172, 1 }, { 109176, 68 }, { 109195, 3 }, { 109229, 68 }, { 109256, 68 }, { 109290, 68 }, { 109304, 68 }, { 109333, 68 }, { 109343, 4 }, { 109347, 7 }, { 109387, 68 }, { 109421, 1 },\n                { 109497, 68 }, { 109501, 3 }, { 109513, 68 }, { 109525, 3 }, { 109625, 4 }, { 109710, 68 }, { 109740, 68 }, { 109751, 68 }, { 109761, 68 }, { 109890, 8 }, { 109891, 4 }, { 109909, 68 }, { 109923, 1 }, { 110017, 68 }, { 110046, 68 }, { 110111, 68 }, { 110258, 68 }, { 110340, 68 }, { 110352, 68 }, { 110398, 68 }, { 110583, 68 },\n                { 110600, 13 }, { 110626, 3 }, { 110709, 68 }, { 110772, 4 }, { 110773, 68 }, { 110813, 1 }, { 110890, 68 }, { 110898, 68 }, { 110954, 68 }, { 111120, 68 }, { 111132, 3 }, { 111163, 8 }, { 111224, 68 }, { 111340, 68 }, { 111398, 68 }, { 111555, 68 }, { 111597, 3 }, { 111607, 68 }, { 111655, 68 }, { 111691, 3 }, { 111835, 68 },\n                { 111854, 68 }, { 111876, 16 }, { 111884, 1 }, { 111884, 56 }, { 111929, 68 }, { 111941, 68 }, { 111969, 68 }, { 112003, 68 }, { 112165, 68 }, { 112365, 68 }, { 112450, 1 }, { 112521, 68 }, { 112649, 4 }, { 112665, 68 }, { 112881, 1 }, { 112882, 68 }, { 112906, 68 }, { 112951, 68 }, { 112994, 68 }, { 112997, 68 }, { 113002, 68 },\n                { 113056, 1 }, { 113077, 68 }, { 113208, 1 }, { 113320, 68 }, { 113326, 3 }, { 113375, 68 }, { 113530, 30 }, { 113530, 30 }, { 113537, 1 }, { 113563, 14 }, { 113592, 68 }, { 113637, 68 }, { 113768, 68 }, { 113850, 5 }, { 113892, 68 }, { 113916, 68 }, { 113965, 68 }, { 113976, 68 }, { 114037, 68 }, { 114149, 1 }, { 114158, 9 },\n                { 114201, 68 }, { 114262, 68 }, { 114268, 4 }, { 114353, 68 }, { 114388, 68 }, { 114404, 68 }, { 114428, 5 }, { 114438, 68 }, { 114541, 68 }, { 114550, 68 }, { 114561, 68 }, { 114625, 3 }, { 114730, 68 }, { 114770, 1 }, { 114815, 4 }, { 114998, 68 }, { 115077, 68 }, { 115093, 68 }, { 115120, 68 }, { 115194, 68 }, { 115216, 3 },\n                { 115299, 68 }, { 115391, 3 }, { 115410, 68 }, { 115542, 33 }, { 115581, 68 }, { 115618, 68 }, { 115645, 23 }, { 115647, 68 }, { 115697, 68 }, { 115725, 68 }, { 115740, 68 }, { 115757, 68 }, { 115763, 68 }, { 115770, 68 }, { 115787, 68 }, { 115916, 68 }, { 115928, 68 }, { 115962, 68 }, { 116020, 68 }, { 116022, 1 }, { 116089, 68 },\n                { 116159, 1 }, { 116196, 68 }, { 116247, 68 }, { 116254, 7 }, { 116336, 68 }, { 116409, 68 }, { 116459, 68 }, { 116569, 68 }, { 116619, 68 }, { 116688, 68 }, { 116733, 68 }, { 116807, 3 }, { 116843, 68 }, { 116886, 1 }, { 116902, 68 }, { 116931, 68 }, { 116952, 68 }, { 116952, 68 }, { 117177, 68 }, { 117189, 68 }, { 117206, 68 },\n                { 117260, 29 }, { 117271, 6 }, { 117276, 3 }, { 117276, 5 }, { 117278, 3 }, { 117278, 68 }, { 117359, 4 }, { 117380, 68 }, { 117414, 1 }, { 117503, 68 }, { 117517, 68 }, { 117530, 68 }, { 117574, 4 }, { 117575, 5 }, { 117577, 68 }, { 117606, 68 }, { 117645, 68 }, { 117655, 68 }, { 117692, 68 }, { 117705, 1 }, { 117731, 1 },\n                { 117762, 4 }, { 117780, 68 }, { 117974, 1 }, { 118057, 1 }, { 118099, 68 }, { 118107, 68 }, { 118113, 68 }, { 118175, 68 }, { 118198, 68 }, { 118232, 45 }, { 118326, 1 }, { 118438, 31 }, { 118469, 68 }, { 118521, 31 }, { 118565, 68 }, { 118593, 68 }, { 118602, 68 }, { 118652, 68 }, { 118668, 68 }, { 118689, 3 }, { 118703, 14 },\n                { 118705, 68 }, { 118813, 68 }, { 118825, 68 }, { 118894, 3 }, { 118915, 68 }, { 118962, 68 }, { 118986, 68 }, { 119045, 68 }, { 119054, 1 }, { 119054, 1 }, { 119119, 68 }, { 119149, 68 }, { 119206, 1 }, { 119316, 68 }, { 119387, 68 }, { 119404, 3 }, { 119516, 68 }, { 119520, 68 }, { 119571, 3 }, { 119573, 68 }, { 119610, 5 },\n                { 119621, 68 }, { 119623, 4 }, { 119672, 68 }, { 119692, 3 }, { 119734, 68 }, { 119742, 1 }, { 119754, 1 }, { 119785, 68 }, { 120001, 68 }, { 120115, 4 }, { 120260, 68 }, { 120314, 68 }, { 120416, 68 }, { 120435, 1 }, { 120450, 3 }, { 120530, 68 }, { 120550, 5 }, { 120730, 68 }, { 120731, 68 }, { 120751, 3 }, { 120755, 68 },\n                { 120869, 68 }, { 120988, 68 }, { 121061, 68 }, { 121177, 68 }, { 121212, 68 }, { 121214, 1 }, { 121286, 68 }, { 121331, 1 }, { 121344, 68 }, { 121407, 68 }, { 121424, 1 }, { 121491, 68 }, { 121568, 76 }, { 121588, 6 }, { 121651, 68 }, { 121676, 68 }, { 121785, 4 }, { 121830, 3 }, { 121919, 1 }, { 121951, 68 }, { 121991, 1 },\n                { 122056, 68 }, { 122062, 68 }, { 122144, 68 }, { 122183, 1 }, { 122331, 68 }, { 122466, 68 }, { 122558, 68 }, { 122570, 68 }, { 122676, 68 }, { 122733, 68 }, { 122774, 6 }, { 122783, 68 }, { 122825, 68 }, { 122865, 68 }, { 122884, 68 }, { 122892, 68 }, { 122911, 68 }, { 122929, 68 }, { 122936, 68 }, { 123190, 68 }, { 123271, 68 },\n                { 123271, 68 }, { 123302, 7 }, { 123391, 68 }, { 123394, 68 }, { 123416, 1 }, { 123708, 68 }, { 123752, 68 }, { 123761, 68 }, { 123783, 68 }, { 123794, 68 }, { 123817, 68 }, { 123820, 1 }, { 123823, 1 }, { 123857, 3 }, { 123886, 56 }, { 124023, 1 }, { 124029, 68 }, { 124042, 68 }, { 124056, 3 }, { 124071, 6 }, { 124105, 5 },\n                { 124143, 68 }, { 124191, 68 }, { 124207, 1 }, { 124257, 68 }, { 124306, 3 }, { 124338, 68 }, { 124388, 8 }, { 124400, 68 }, { 124418, 68 }, { 124502, 68 }, { 124521, 1 }, { 124533, 68 }, { 124645, 68 }, { 124685, 1 }, { 124694, 68 }, { 124700, 1 }, { 124736, 68 }, { 124891, 7 }, { 124920, 68 }, { 124983, 68 }, { 125014, 68 },\n                { 125038, 68 }, { 125084, 68 }, { 125162, 68 }, { 125193, 68 }, { 125285, 68 }, { 125368, 68 }, { 125409, 68 }, { 125570, 68 }, { 125601, 68 }, { 125641, 1 }, { 125721, 68 }, { 125731, 68 }, { 125803, 68 }, { 125904, 68 }, { 125973, 68 }, { 126018, 1 }, { 126034, 5 }, { 126094, 1 }, { 126144, 1 }, { 126195, 68 }, { 126297, 68 },\n                { 126389, 68 }, { 126429, 68 }, { 126439, 68 }, { 126499, 68 }, { 126501, 1 }, { 126587, 68 }, { 126663, 68 }, { 126681, 68 }, { 126687, 1 }, { 126781, 68 }, { 126783, 68 }, { 126840, 8 }, { 126843, 68 }, { 126959, 68 }, { 127015, 68 }, { 127101, 68 }, { 127149, 68 }, { 127197, 54 }, { 127268, 68 }, { 127372, 68 }, { 127385, 68 },\n                { 127473, 4 }, { 127539, 68 }, { 127598, 68 }, { 127613, 14 }, { 127683, 3 }, { 127684, 68 }, { 127697, 68 }, { 127698, 3 }, { 127773, 68 }, { 127781, 1 }, { 127839, 68 }, { 127905, 68 }, { 127949, 68 }, { 128035, 68 }, { 128046, 1 }, { 128167, 68 }, { 128271, 68 }, { 128307, 1 }, { 128320, 68 }, { 128330, 68 }, { 128375, 68 },\n                { 128381, 4 }, { 128447, 68 }, { 128462, 68 }, { 128466, 3 }, { 128466, 68 }, { 128496, 68 }, { 128589, 68 }, { 128616, 3 }, { 128679, 1 }, { 128770, 1 }, { 128793, 68 }, { 128802, 68 }, { 128813, 68 }, { 128900, 68 }, { 128949, 68 }, { 129269, 68 }, { 129271, 3 }, { 129278, 68 }, { 129343, 1 }, { 129408, 67 }, { 129408, 1 },\n                { 129421, 6 }, { 129461, 68 }, { 129469, 3 }, { 129482, 68 }, { 129502, 68 }, { 129512, 68 }, { 129551, 68 }, { 129629, 68 }, { 129632, 68 }, { 129679, 1 }, { 129725, 68 }, { 130007, 68 }, { 130018, 16 }, { 130057, 68 }, { 130071, 68 }, { 130087, 68 }, { 130188, 1 }, { 130202, 68 }, { 130316, 68 }, { 130328, 1 }, { 130466, 68 },\n                { 130549, 68 }, { 130649, 68 }, { 130705, 3 }, { 130800, 68 }, { 130907, 68 }, { 130989, 68 }, { 131103, 68 }, { 131127, 68 }, { 131200, 5 }, { 131241, 6 }, { 131351, 68 }, { 131413, 68 }, { 131448, 68 }, { 131599, 68 }, { 131634, 1 }, { 131687, 68 }, { 131739, 68 }, { 131758, 68 }, { 131765, 68 }, { 131787, 3 }, { 131819, 3 },\n                { 131868, 68 }, { 131886, 68 }, { 131901, 4 }, { 131977, 68 }, { 131990, 68 }, { 132035, 68 }, { 132035, 68 }, { 132043, 68 }, { 132173, 68 }, { 132181, 4 }, { 132181, 6 }, { 132194, 5 }, { 132252, 68 }, { 132262, 6 }, { 132271, 1 }, { 132285, 68 }, { 132328, 68 }, { 132335, 1 }, { 132337, 1 }, { 132389, 5 }, { 132430, 68 },\n                { 132451, 68 }, { 132499, 87 }, { 132503, 1 }, { 132520, 4 }, { 132541, 4 }, { 132860, 68 }, { 132862, 4 }, { 132874, 168 }, { 132874, 13 }, { 132875, 168 }, { 132911, 68 }, { 132973, 68 }, { 133051, 68 }, { 133062, 68 }, { 133067, 68 }, { 133138, 68 }, { 133184, 68 }, { 133231, 68 }, { 133297, 3 }, { 133344, 68 }, { 133385, 4 },\n                { 133408, 68 }, { 133464, 68 }, { 133522, 68 }, { 133631, 68 }, { 133631, 68 }, { 133702, 68 }, { 133705, 1 }, { 133721, 68 }, { 133746, 68 }, { 133773, 3 }, { 133819, 68 }, { 133843, 68 }, { 133929, 68 }, { 133946, 68 }, { 134113, 4 }, { 134151, 68 }, { 134289, 1 }, { 134385, 68 }, { 134429, 68 }, { 134506, 68 }, { 134511, 68 },\n                { 134521, 68 }, { 134558, 1 }, { 134710, 68 }, { 134738, 68 }, { 134751, 3 }, { 134818, 68 }, { 134820, 4 }, { 134879, 68 }, { 134919, 68 }, { 134947, 68 }, { 134948, 3 }, { 135040, 3 }, { 135125, 10 }, { 135155, 68 }, { 135228, 68 }, { 135255, 68 }, { 135296, 3 }, { 135322, 68 }, { 135349, 68 }, { 135428, 3 }, { 135476, 1 },\n                { 135503, 68 }, { 135524, 68 }, { 135550, 4 }, { 135594, 68 }, { 135597, 68 }, { 135624, 3 }, { 135741, 68 }, { 135753, 68 }, { 135842, 68 }, { 135853, 68 }, { 135896, 3 }, { 136004, 1 }, { 136061, 1 }, { 136068, 1 }, { 136106, 68 }, { 136145, 68 }, { 136145, 68 }, { 136173, 68 }, { 136186, 68 }, { 136196, 68 }, { 136201, 68 },\n                { 136211, 68 }, { 136268, 68 }, { 136298, 68 }, { 136377, 68 }, { 136420, 68 }, { 136475, 23 }, { 136486, 1 }, { 136554, 68 }, { 136641, 68 }, { 136770, 1 }, { 136873, 68 }, { 136877, 1 }, { 136906, 68 }, { 137092, 68 }, { 137143, 68 }, { 137200, 3 }, { 137232, 68 }, { 137239, 68 }, { 137248, 68 }, { 137281, 1 }, { 137301, 68 },\n                { 137314, 3 }, { 137352, 1 }, { 137365, 68 }, { 137375, 68 }, { 137411, 68 }, { 137424, 68 }, { 137516, 68 }, { 137532, 68 }, { 137593, 68 }, { 137600, 68 }, { 137658, 68 }, { 137703, 68 }, { 137766, 68 }, { 137791, 68 }, { 137801, 68 }, { 137864, 68 }, { 137870, 3 }, { 137931, 68 }, { 138009, 3 }, { 138013, 1 }, { 138013, 1 },\n                { 138066, 68 }, { 138073, 68 }, { 138114, 68 }, { 138150, 68 }, { 138236, 68 }, { 138276, 68 }, { 138286, 68 }, { 138298, 3 }, { 138309, 1 }, { 138373, 3 }, { 138524, 68 }, { 138535, 1 }, { 138593, 4 }, { 138611, 1 }, { 138725, 68 }, { 138807, 68 }, { 138819, 3 }, { 138849, 5 }, { 138867, 68 }, { 138907, 68 }, { 138930, 3 },\n                { 139026, 68 }, { 139102, 68 }, { 139108, 3 }, { 139184, 1 }, { 139209, 3 }, { 139282, 68 }, { 139289, 4 }, { 139382, 1 }, { 139421, 1 }, { 139436, 68 }, { 139450, 1 }, { 139523, 3 }, { 139533, 68 }, { 139590, 68 }, { 139590, 68 }, { 139722, 68 }, { 139785, 68 }, { 139785, 1 }, { 139798, 68 }, { 139813, 68 }, { 139868, 68 },\n                { 139935, 3 }, { 139990, 3 }, { 140050, 68 }, { 140177, 68 }, { 140177, 4 }, { 140408, 68 }, { 140420, 3 }, { 140461, 68 }, { 140578, 15 }, { 140605, 1368 }, { 140662, 1 }, { 140755, 68 }, { 140786, 68 }, { 140846, 68 }, { 140874, 68 }, { 140959, 1 }, { 140973, 68 }, { 141128, 68 }, { 141132, 68 }, { 141257, 68 }, { 141290, 1 },\n                { 141360, 68 }, { 141472, 68 }, { 141545, 68 }, { 141545, 68 }, { 141575, 1 }, { 141606, 5 }, { 141655, 68 }, { 141735, 68 }, { 141767, 5 }, { 141796, 68 }, { 141841, 68 }, { 141915, 68 }, { 141923, 1 }, { 141932, 68 }, { 141994, 68 }, { 142018, 68 }, { 142029, 3 }, { 142072, 68 }, { 142128, 68 }, { 142133, 1 }, { 142261, 68 },\n                { 142304, 1 }, { 142400, 68 }, { 142401, 68 }, { 142409, 68 }, { 142479, 68 }, { 142522, 1 }, { 142552, 1 }, { 142589, 68 }, { 142596, 68 }, { 142753, 1 }, { 142766, 68 }, { 142796, 68 }, { 142836, 68 }, { 142871, 68 }, { 143058, 3 }, { 143059, 6 }, { 143063, 3 }, { 143065, 68 }, { 143141, 4 }, { 143173, 68 }, { 143374, 68 },\n                { 143399, 68 }, { 143406, 68 }, { 143429, 3 }, { 143430, 68 }, { 143462, 1 }, { 143579, 68 }, { 143663, 68 }, { 143844, 3 }, { 143851, 68 }, { 143926, 68 }, { 143931, 68 }, { 144051, 6 }, { 144085, 10 }, { 144147, 68 }, { 144188, 4 }, { 144238, 4 }, { 144353, 68 }, { 144465, 68 }, { 144474, 68 }, { 144637, 68 }, { 144638, 1 },\n                { 144648, 1 }, { 144661, 3 }, { 144812, 68 }, { 144847, 68 }, { 144901, 8 }, { 145058, 68 }, { 145122, 8 }, { 145134, 68 }, { 145150, 68 }, { 145299, 1 }, { 145313, 68 }, { 145314, 3 }, { 145374, 68 }, { 145412, 68 }, { 145432, 68 }, { 145446, 68 }, { 145534, 3 }, { 145592, 68 }, { 145614, 68 }, { 145648, 68 }, { 145721, 68 },\n                { 145858, 1 }, { 145970, 3 }, { 145984, 3 }, { 146004, 68 }, { 146016, 3 }, { 146048, 68 }, { 146097, 3 }, { 146103, 68 }, { 146136, 68 }, { 146194, 3 }, { 146230, 1 }, { 146254, 68 }, { 146261, 4 }, { 146269, 4 }, { 146393, 68 }, { 146411, 3 }, { 146501, 68 }, { 146547, 68 }, { 146547, 68 }, { 146573, 68 }, { 146616, 68 },\n                { 146622, 3 }, { 146728, 3 }, { 146781, 5 }, { 146805, 4 }, { 146921, 68 }, { 147002, 3 }, { 147072, 68 }, { 147159, 68 }, { 147170, 68 }, { 147203, 1 }, { 147245, 68 }, { 147278, 68 }, { 147422, 68 }, { 147471, 68 }, { 147491, 68 }, { 147607, 23 }, { 147693, 68 }, { 147763, 68 }, { 147775, 6 }, { 147776, 4 }, { 147824, 68 },\n                { 147922, 68 }, { 147922, 68 }, { 147937, 68 }, { 147957, 68 }, { 147980, 68 }, { 148008, 68 }, { 148018, 68 }, { 148046, 3 }, { 148071, 4 }, { 148106, 3 }, { 148122, 68 }, { 148139, 68 }, { 148175, 68 }, { 164238, 18 }, { 164315, 28 }, { 164449, 28 }, { 164529, 28 }, { 164574, 348 }, { 164591, 968 }, { 164595, 28 },\n                { 164611, 28 }, { 164623, 48 }, { 164632, 108 }, { 164691, 28 }, { 164706, 28 }, { 164755, 28 }, { 164761, 28 }, { 164973, 28 }, { 165030, 28 }, { 165090, 28 }, { 165099, 18 }, { 165126, 28 }, { 165188, 28 }, { 165205, 28 }, { 165275, 18 }, { 165347, 28 }, { 165381, 28 }, { 165562, 28 }, { 165563, 18 }, { 165594, 568 },\n                { 165641, 868 }, { 165663, 68 }, { 165759, 28 }, { 165811, 28 }, { 165822, 18 }, { 165830, 18 }, { 165903, 18 }, { 165921, 28 }, { 165953, 18 }, { 166022, 18 }, { 166294, 28 }, { 166333, 28 }, { 166420, 28 }, { 166433, 28 }, { 166442, 18 }, { 166536, 28 }, { 166543, 28 }, { 166556, 28 }, { 166571, 28 }, { 166575, 18 },\n                { 166588, 28 }, { 166601, 678 }, { 166663, 788 }, { 166692, 18 }, { 166710, 28 }, { 166759, 28 }, { 166785, 38 }, { 166842, 28 }, { 166843, 28 }, { 166864, 28 }, { 166902, 28 }, { 166996, 28 }, { 166999, 28 }, { 167038, 28 }, { 167112, 48 }, { 167112, 28 }, { 167177, 28 }, { 167180, 28 }, { 167229, 18 }, { 167298, 28 },\n                { 167306, 48 }, { 167309, 38 }, { 167402, 28 }, { 167405, 878 }, { 167433, 568 }, { 167435, 18 }, { 167461, 38 }, { 167553, 38 }, { 167688, 58 }, { 167689, 28 }, { 167709, 28 }, { 167744, 28 }, { 167821, 28 }, { 167825, 28 }, { 167925, 108 }, { 167969, 28 }, { 168024, 28 }, { 168089, 28 }, { 168104, 28 }, { 168194, 28 },\n                { 168305, 28 }, { 168316, 28 }, { 168366, 28 }, { 168423, 28 }, { 168568, 38 }, { 168582, 558 }, { 168615, 768 }, { 168618, 28 }, { 168638, 28 }, { 168671, 28 }, { 168736, 28 }, { 168747, 28 }, { 168750, 48 }, { 168808, 38 }, { 168814, 48 }, { 168820, 28 }, { 168914, 28 }, { 168968, 28 }, { 168979, 28 }, { 169006, 28 },\n                { 169069, 28 }, { 169106, 38 }, { 169158, 28 }, { 169158, 28 }, { 169189, 28 }, { 169253, 28 }, { 169259, 18 }, { 169279, 658 }, { 169325, 568 }, { 169349, 28 }, { 169353, 28 }, { 169378, 28 }, { 169432, 28 }, { 169476, 18 }, { 169476, 18 }, { 169525, 28 }, { 169538, 78 }, { 169555, 28 }, { 169571, 28 }, { 169594, 48 },\n                { 169687, 28 }, { 169799, 28 }, { 169831, 28 }, { 170042, 28 }, { 170061, 28 }, { 170065, 18 }, { 170128, 68 }, { 170148, 208 }, { 170215, 708 }, { 170256, 608 }, { 170266, 698 }, { 170275, 78 }, { 170277, 68 }, { 170500, 38 }, { 170516, 38 }, { 170601, 28 }, { 170666, 28 }, { 170668, 48 }, { 170668, 18 }, { 170716, 38 },\n                { 170728, 38 }, { 170735, 58 }, { 170847, 38 }, { 170852, 98 }, { 170858, 438 }, { 170859, 568 }, { 170956, 568 }, { 170956, 18 }, { 170967, 28 }, { 171005, 28 }, { 171113, 28 }, { 171279, 28 }, { 171400, 28 }, { 171405, 28 }, { 171448, 18 }, { 171490, 28 }, { 171567, 328 }, { 171590, 28 }, { 171723, 28 }, { 171737, 38 },\n                { 171958, 28 }, { 171967, 68 }, { 164238, 18 }, { 164315, 28 }, { 164449, 28 }, { 164529, 28 }, { 164574, 348 }, { 164591, 968 }, { 164595, 28 }, { 164611, 28 }, { 164623, 48 }, { 164632, 108 }, { 164691, 28 }, { 164706, 28 }, { 164755, 28 }, { 164761, 28 }, { 164973, 28 }, { 165030, 28 }, { 165090, 28 }, { 165099, 18 },\n                { 165126, 28 }, { 165188, 28 }, { 165205, 28 }, { 165275, 18 }, { 165347, 28 }, { 165381, 28 }, { 165562, 28 }, { 165563, 18 }, { 165594, 568 }, { 165641, 868 }, { 165663, 68 }, { 165759, 28 }, { 165811, 28 }, { 165822, 18 }, { 165830, 18 }, { 165903, 18 }, { 165921, 28 }, { 165953, 18 }, { 166022, 18 }, { 166294, 28 },\n                { 166333, 28 }, { 166420, 28 }, { 166433, 28 }, { 166442, 18 }, { 166536, 28 }, { 166543, 28 }, { 166556, 28 }, { 166571, 28 }, { 166575, 18 }, { 166588, 28 }, { 166601, 678 }, { 166663, 788 }, { 166692, 18 }, { 166710, 28 }, { 166759, 28 }, { 166785, 38 }, { 166842, 28 }, { 166843, 28 }, { 166864, 28 }, { 166902, 28 },\n                { 166996, 28 }, { 166999, 28 }, { 167038, 28 }, { 167112, 48 }, { 167112, 28 }, { 167177, 28 }, { 167180, 28 }, { 167229, 18 }, { 167298, 28 }, { 167306, 48 }, { 167309, 38 }, { 167402, 28 }, { 167405, 878 }, { 167433, 568 }, { 167435, 18 }, { 167461, 38 }, { 167553, 38 }, { 167688, 58 }, { 167689, 28 }, { 167709, 28 },\n                { 167744, 28 }, { 167821, 28 }, { 167825, 28 }, { 167925, 108 }, { 167969, 28 }, { 168024, 28 }, { 168089, 28 }, { 168104, 28 }, { 168194, 28 }, { 168305, 28 }, { 168316, 28 }, { 168366, 28 }, { 168423, 28 }, { 168568, 38 }, { 168582, 558 }, { 168615, 768 }, { 168618, 28 }, { 168638, 28 }, { 168671, 28 }, { 168736, 28 },\n                { 168747, 28 }, { 168750, 48 }, { 168808, 38 }, { 168814, 48 }, { 168820, 28 }, { 168914, 28 }, { 168968, 28 }, { 168979, 28 }, { 169006, 28 }, { 169069, 28 }, { 169106, 38 }, { 169158, 28 }, { 169158, 28 }, { 169189, 28 }, { 169253, 28 }, { 169259, 18 }, { 169279, 658 }, { 169325, 568 }, { 169349, 28 }, { 169353, 28 },\n                { 169378, 28 }, { 169432, 28 }, { 169476, 18 }, { 169476, 18 }, { 169525, 28 }, { 169538, 78 }, { 169555, 28 }, { 169571, 28 }, { 169594, 48 }, { 169687, 28 }, { 169799, 28 }, { 169831, 28 }, { 170042, 28 }, { 170061, 28 }, { 170065, 18 }, { 170128, 68 }, { 170148, 208 }, { 170215, 708 }, { 170256, 608 }, { 170266, 698 },\n                { 170275, 78 }, { 170277, 68 }, { 170500, 38 }, { 170516, 38 }, { 170601, 28 }, { 170666, 28 }, { 170668, 48 }, { 170668, 18 }, { 170716, 38 }, { 170728, 38 }, { 170735, 58 }, { 170847, 38 }, { 170852, 98 }, { 170858, 438 }, { 170859, 568 }, { 170956, 568 }, { 170956, 18 }, { 170967, 28 }, { 171005, 28 }, { 171113, 28 },\n                { 171279, 28 }, { 171400, 28 }, { 171405, 28 }, { 171448, 18 }, { 171490, 28 }, { 171567, 328 }, { 171590, 28 }, { 171723, 28 }, { 171737, 38 }, { 171958, 28 }, { 171967, 2 } };\n    }\n}"
  },
  {
    "path": "hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixTimerTest.java",
    "content": "/**\n * Copyright 2015 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.util;\n\nimport com.netflix.hystrix.HystrixTimerThreadPoolProperties;\nimport com.netflix.hystrix.strategy.HystrixPlugins;\nimport com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;\nimport com.netflix.hystrix.util.HystrixTimer.ScheduledExecutor;\nimport com.netflix.hystrix.util.HystrixTimer.TimerListener;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.lang.ref.Reference;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.*;\n\n\npublic class HystrixTimerTest {\n\n    @Before\n    public void setUp() {\n        HystrixTimer timer = HystrixTimer.getInstance();\n        HystrixTimer.reset();\n        HystrixPlugins.reset();\n    }\n\n    @After\n    public void tearDown() {\n        HystrixPlugins.reset();\n    }\n\n    @Test\n    public void testSingleCommandSingleInterval() {\n        HystrixTimer timer = HystrixTimer.getInstance();\n        TestListener l1 = new TestListener(50, \"A\");\n        timer.addTimerListener(l1);\n\n        TestListener l2 = new TestListener(50, \"B\");\n        timer.addTimerListener(l2);\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        // we should have 7 or more 50ms ticks within 500ms\n        System.out.println(\"l1 ticks: \" + l1.tickCount.get());\n        System.out.println(\"l2 ticks: \" + l2.tickCount.get());\n        assertTrue(l1.tickCount.get() > 7);\n        assertTrue(l2.tickCount.get() > 7);\n    }\n\n    @Test\n    public void testSingleCommandMultipleIntervals() {\n        HystrixTimer timer = HystrixTimer.getInstance();\n        TestListener l1 = new TestListener(100, \"A\");\n        timer.addTimerListener(l1);\n\n        TestListener l2 = new TestListener(10, \"B\");\n        timer.addTimerListener(l2);\n\n        TestListener l3 = new TestListener(25, \"C\");\n        timer.addTimerListener(l3);\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        // we should have 3 or more 100ms ticks within 500ms\n        System.out.println(\"l1 ticks: \" + l1.tickCount.get());\n        assertTrue(l1.tickCount.get() >= 3);\n        // but it can't be more than 6\n        assertTrue(l1.tickCount.get() < 6);\n\n        // we should have 30 or more 10ms ticks within 500ms\n        System.out.println(\"l2 ticks: \" + l2.tickCount.get());\n        assertTrue(l2.tickCount.get() > 30);\n        assertTrue(l2.tickCount.get() < 550);\n\n        // we should have 15-20 25ms ticks within 500ms\n        System.out.println(\"l3 ticks: \" + l3.tickCount.get());\n        assertTrue(l3.tickCount.get() > 14);\n        assertTrue(l3.tickCount.get() < 25);\n    }\n\n    @Test\n    public void testSingleCommandRemoveListener() {\n        HystrixTimer timer = HystrixTimer.getInstance();\n        TestListener l1 = new TestListener(50, \"A\");\n        timer.addTimerListener(l1);\n\n        TestListener l2 = new TestListener(50, \"B\");\n        Reference<TimerListener> l2ref = timer.addTimerListener(l2);\n\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        // we should have 7 or more 50ms ticks within 500ms\n        System.out.println(\"l1 ticks: \" + l1.tickCount.get());\n        System.out.println(\"l2 ticks: \" + l2.tickCount.get());\n        assertTrue(l1.tickCount.get() > 7);\n        assertTrue(l2.tickCount.get() > 7);\n\n        // remove l2\n        l2ref.clear();\n\n        // reset counts\n        l1.tickCount.set(0);\n        l2.tickCount.set(0);\n\n        // wait for time to pass again\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        // we should have 7 or more 50ms ticks within 500ms\n        System.out.println(\"l1 ticks: \" + l1.tickCount.get());\n        System.out.println(\"l2 ticks: \" + l2.tickCount.get());\n        // l1 should continue ticking\n        assertTrue(l1.tickCount.get() > 7);\n        // we should have no ticks on l2 because we removed it\n        System.out.println(\"tickCount.get(): \" + l2.tickCount.get() + \" on l2: \" + l2);\n        assertEquals(0, l2.tickCount.get());\n    }\n\n    @Test\n    public void testReset() {\n        HystrixTimer timer = HystrixTimer.getInstance();\n        TestListener l1 = new TestListener(50, \"A\");\n        timer.addTimerListener(l1);\n\n        ScheduledExecutor ex = timer.executor.get();\n\n        assertFalse(ex.executor.isShutdown());\n\n        // perform reset which should shut it down\n        HystrixTimer.reset();\n\n        assertTrue(ex.executor.isShutdown());\n        assertNull(timer.executor.get());\n\n        // assert it starts up again on use\n        TestListener l2 = new TestListener(50, \"A\");\n        timer.addTimerListener(l2);\n\n        ScheduledExecutor ex2 = timer.executor.get();\n\n        assertFalse(ex2.executor.isShutdown());\n\n        // reset again to shutdown what we just started\n        HystrixTimer.reset();\n        // try resetting again to make sure it's idempotent (ie. doesn't blow up on an NPE)\n        HystrixTimer.reset();\n    }\n\n    @Test\n    public void testThreadPoolSizeDefault() {\n\n        HystrixTimer hystrixTimer = HystrixTimer.getInstance();\n        hystrixTimer.startThreadIfNeeded();\n        assertEquals(Runtime.getRuntime().availableProcessors(), hystrixTimer.executor.get().getThreadPool().getCorePoolSize());\n    }\n\n    @Test\n    public void testThreadPoolSizeConfiguredWithBuilder() {\n\n        HystrixTimerThreadPoolProperties.Setter builder = HystrixTimerThreadPoolProperties.Setter().withCoreSize(1);\n        final HystrixTimerThreadPoolProperties props = new HystrixTimerThreadPoolProperties(builder) {\n        };\n\n        HystrixPropertiesStrategy strategy = new HystrixPropertiesStrategy() {\n            @Override\n            public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() {\n                return props;\n            }\n        };\n\n        HystrixPlugins.getInstance().registerPropertiesStrategy(strategy);\n\n        HystrixTimer hystrixTimer = HystrixTimer.getInstance();\n        hystrixTimer.startThreadIfNeeded();\n\n        assertEquals(1, hystrixTimer.executor.get().getThreadPool().getCorePoolSize());\n\n    }\n\n    private static class TestListener implements TimerListener {\n\n        private final int interval;\n        AtomicInteger tickCount = new AtomicInteger();\n\n        TestListener(int interval, String value) {\n            this.interval = interval;\n        }\n\n        @Override\n        public void tick() {\n            tickCount.incrementAndGet();\n        }\n\n        @Override\n        public int getIntervalTimeInMilliseconds() {\n            return interval;\n        }\n\n    }\n\n    public static void main(String args[]) {\n        PlayListener l1 = new PlayListener();\n        PlayListener l2 = new PlayListener();\n        PlayListener l3 = new PlayListener();\n        PlayListener l4 = new PlayListener();\n        PlayListener l5 = new PlayListener();\n\n        Reference<TimerListener> ref = HystrixTimer.getInstance().addTimerListener(l1);\n        HystrixTimer.getInstance().addTimerListener(l2);\n        HystrixTimer.getInstance().addTimerListener(l3);\n\n        HystrixTimer.getInstance().addTimerListener(l4);\n\n        try {\n            Thread.sleep(5000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        ref.clear();\n        HystrixTimer.getInstance().addTimerListener(l5);\n\n        try {\n            Thread.sleep(10000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        System.out.println(\"counter: \" + l1.counter);\n        System.out.println(\"counter: \" + l2.counter);\n        System.out.println(\"counter: \" + l3.counter);\n        System.out.println(\"counter: \" + l4.counter);\n        System.out.println(\"counter: \" + l5.counter);\n\n    }\n\n    public static class PlayListener implements TimerListener {\n        int counter = 0;\n\n        @Override\n        public void tick() {\n            counter++;\n        }\n\n        @Override\n        public int getIntervalTimeInMilliseconds() {\n            return 10;\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "hystrix-core/src/test/resources/FAKE_META_INF_SERVICES/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties",
    "content": "com.netflix.hystrix.strategy.HystrixPluginsTest$MockHystrixDynamicPropertiesTest"
  },
  {
    "path": "hystrix-core/src/test/resources/FAKE_META_INF_SERVICES/com.netflix.hystrix.strategy.properties.HystrixDynamicPropertiesFail",
    "content": "FAILDONOTWORK"
  },
  {
    "path": "hystrix-examples/README.md",
    "content": "## hystrix-examples\n\nThis module contains examples of using [HystrixCommand](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java), [HystrixCollapser](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapser.java) and other aspects of Hystrix.\n\n## Documentation\n\nDocumentation related to the examples in this module is on the [How To Use](https://github.com/Netflix/Hystrix/wiki/How-To-Use) page.\n\n## Demo\n\nTo run a [demo app](https://github.com/Netflix/Hystrix/tree/master/hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/HystrixCommandDemo.java) do the following:\n\n```\n$ git clone git@github.com:Netflix/Hystrix.git\n$ cd Hystrix/\n./gradlew runDemo\n```\n\nYou will see output similar to the following:\n\n```\nRequest => GetUserAccountCommand[SUCCESS][8ms], GetPaymentInformationCommand[SUCCESS][20ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][101ms], CreditCardCommand[SUCCESS][1075ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][2ms], GetPaymentInformationCommand[SUCCESS][22ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][130ms], CreditCardCommand[SUCCESS][1050ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][4ms], GetPaymentInformationCommand[SUCCESS][19ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][145ms], CreditCardCommand[SUCCESS][1301ms]\nRequest => GetUserAccountCommand[SUCCESS][4ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][93ms], CreditCardCommand[SUCCESS][1409ms]\n\n#####################################################################################\n# CreditCardCommand: Requests: 17 Errors: 0 (0%)   Mean: 1171 75th: 1391 90th: 1470 99th: 1486 \n# GetOrderCommand: Requests: 21 Errors: 0 (0%)   Mean: 100 75th: 144 90th: 207 99th: 230 \n# GetUserAccountCommand: Requests: 21 Errors: 4 (19%)   Mean: 8 75th: 11 90th: 46 99th: 51 \n# GetPaymentInformationCommand: Requests: 21 Errors: 0 (0%)   Mean: 18 75th: 21 90th: 24 99th: 25 \n#####################################################################################\n\nRequest => GetUserAccountCommand[SUCCESS][10ms], GetPaymentInformationCommand[SUCCESS][16ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][51ms], CreditCardCommand[SUCCESS][922ms]\nRequest => GetUserAccountCommand[SUCCESS][12ms], GetPaymentInformationCommand[SUCCESS][12ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][68ms], CreditCardCommand[SUCCESS][1257ms]\nRequest => GetUserAccountCommand[SUCCESS][10ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][78ms], CreditCardCommand[SUCCESS][1295ms]\nRequest => GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS][6ms], GetPaymentInformationCommand[SUCCESS][11ms], GetUserAccountCommand[FAILURE, FALLBACK_SUCCESS, RESPONSE_FROM_CACHE][0ms]x2, GetOrderCommand[SUCCESS][153ms], CreditCardCommand[SUCCESS][1321ms]\n```\n\nThis demo simulates 4 different [HystrixCommand](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java) implementations with failures, latency, timeouts and duplicate calls in a multi-threaded environment.\n\nIt logs the results of [HystrixRequestLog](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java) and metrics from [HystrixCommandMetrics](https://github.com/Netflix/Hystrix/tree/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandMetrics.java).\n\n\n\n## Maven Central\n\nBinaries and dependencies for this module can be found on [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.netflix.hystrix%22%20AND%20a%3A%22hystrix-examples%22).\n\n__GroupId: com.netflix.hystrix__  \n__ArtifactId: hystrix-examples__  \n\nExample for Maven:\n\n```xml\n<dependency>\n    <groupId>com.netflix.hystrix</groupId>\n    <artifactId>hystrix-examples</artifactId>\n    <version>1.0.2</version>\n</dependency>\n```\nand for Ivy:\n\n```xml\n<dependency org=\"com.netflix.hystrix\" name=\"hystrix-examples\" rev=\"1.0.2\" />\n```\n"
  },
  {
    "path": "hystrix-examples/build.gradle",
    "content": "dependencies {\n    api project(':hystrix-core')\n    compileOnly 'junit:junit-dep:4.10'\n}\n\ntask(runDemo, dependsOn: 'classes', type: JavaExec) {\n\tmain = 'com.netflix.hystrix.examples.demo.HystrixCommandDemo'\n\tclasspath = sourceSets.main.runtimeClasspath\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandCollapserGetValueForKey.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCollapser;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Sample {@link HystrixCollapser} that automatically batches multiple requests to execute()/queue()\n * into a single {@link HystrixCommand} execution for all requests within the defined batch (time or size).\n */\npublic class CommandCollapserGetValueForKey extends HystrixCollapser<List<String>, String, Integer> {\n\n    private final Integer key;\n\n    public CommandCollapserGetValueForKey(Integer key) {\n        this.key = key;\n    }\n\n    @Override\n    public Integer getRequestArgument() {\n        return key;\n    }\n\n    @Override\n    protected HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, Integer>> requests) {\n        return new BatchCommand(requests);\n    }\n\n    @Override\n    protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) {\n        int count = 0;\n        for (CollapsedRequest<String, Integer> request : requests) {\n            request.setResponse(batchResponse.get(count++));\n        }\n    }\n\n    private static final class BatchCommand extends HystrixCommand<List<String>> {\n        private final Collection<CollapsedRequest<String, Integer>> requests;\n\n        private BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(\"GetValueForKey\")));\n            this.requests = requests;\n        }\n\n        @Override\n        protected List<String> run() {\n            ArrayList<String> response = new ArrayList<String>();\n            for (CollapsedRequest<String, Integer> request : requests) {\n                // artificial response for each argument received in the batch\n                response.add(\"ValueForKey: \" + request.getArgument());\n            }\n            return response;\n        }\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testCollapser() throws Exception {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                Future<String> f1 = new CommandCollapserGetValueForKey(1).queue();\n                Future<String> f2 = new CommandCollapserGetValueForKey(2).queue();\n                Future<String> f3 = new CommandCollapserGetValueForKey(3).queue();\n                Future<String> f4 = new CommandCollapserGetValueForKey(4).queue();\n\n                assertEquals(\"ValueForKey: 1\", f1.get());\n                assertEquals(\"ValueForKey: 2\", f2.get());\n                assertEquals(\"ValueForKey: 3\", f3.get());\n                assertEquals(\"ValueForKey: 4\", f4.get());\n\n                int numExecuted = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size();\n\n                System.err.println(\"num executed: \" + numExecuted);\n\n                // assert that the batch command 'GetValueForKey' was in fact executed and that it executed only \n                // once or twice (due to non-determinism of scheduler since this example uses the real timer)\n                if (numExecuted > 2) {\n                    fail(\"some of the commands should have been collapsed\");\n                }\n\n                System.err.println(\"HystrixRequestLog.getCurrentRequest().getAllExecutedCommands(): \" + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());\n\n                int numLogs = 0;\n                for (HystrixInvokableInfo<?> command : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) {\n                    numLogs++;\n                    \n                    // assert the command is the one we're expecting\n                    assertEquals(\"GetValueForKey\", command.getCommandKey().name());\n\n                    System.err.println(command.getCommandKey().name() + \" => command.getExecutionEvents(): \" + command.getExecutionEvents());\n\n                    // confirm that it was a COLLAPSED command execution\n                    assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));\n                    assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));\n                }\n\n                assertEquals(numExecuted, numLogs);\n            } finally {\n                context.shutdown();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandFacadeWithPrimarySecondary.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.config.DynamicBooleanProperty;\nimport com.netflix.config.DynamicPropertyFactory;\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Sample {@link HystrixCommand} pattern using a semaphore-isolated command\n * that conditionally invokes thread-isolated commands.\n */\npublic class CommandFacadeWithPrimarySecondary extends HystrixCommand<String> {\n\n    private final static DynamicBooleanProperty usePrimary = DynamicPropertyFactory.getInstance().getBooleanProperty(\"primarySecondary.usePrimary\", true);\n\n    private final int id;\n\n    public CommandFacadeWithPrimarySecondary(int id) {\n        super(Setter\n                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"SystemX\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"PrimarySecondaryCommand\"))\n                .andCommandPropertiesDefaults(\n                        // we want to default to semaphore-isolation since this wraps\n                        // 2 others commands that are already thread isolated\n                        HystrixCommandProperties.Setter()\n                                .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));\n        this.id = id;\n    }\n\n    @Override\n    protected String run() {\n        if (usePrimary.get()) {\n            return new PrimaryCommand(id).execute();\n        } else {\n            return new SecondaryCommand(id).execute();\n        }\n    }\n\n    @Override\n    protected String getFallback() {\n        return \"static-fallback-\" + id;\n    }\n\n    @Override\n    protected String getCacheKey() {\n        return String.valueOf(id);\n    }\n\n    private static class PrimaryCommand extends HystrixCommand<String> {\n\n        private final int id;\n\n        private PrimaryCommand(int id) {\n            super(Setter\n                    .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"SystemX\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(\"PrimaryCommand\"))\n                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(\"PrimaryCommand\"))\n                    .andCommandPropertiesDefaults(\n                            // we default to a 600ms timeout for primary\n                            HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(600)));\n            this.id = id;\n        }\n\n        @Override\n        protected String run() {\n            // perform expensive 'primary' service call\n            return \"responseFromPrimary-\" + id;\n        }\n\n    }\n\n    private static class SecondaryCommand extends HystrixCommand<String> {\n\n        private final int id;\n\n        private SecondaryCommand(int id) {\n            super(Setter\n                    .withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"SystemX\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(\"SecondaryCommand\"))\n                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(\"SecondaryCommand\"))\n                    .andCommandPropertiesDefaults(\n                            // we default to a 100ms timeout for secondary\n                            HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)));\n            this.id = id;\n        }\n\n        @Override\n        protected String run() {\n            // perform fast 'secondary' service call\n            return \"responseFromSecondary-\" + id;\n        }\n\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testPrimary() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                ConfigurationManager.getConfigInstance().setProperty(\"primarySecondary.usePrimary\", true);\n                assertEquals(\"responseFromPrimary-20\", new CommandFacadeWithPrimarySecondary(20).execute());\n            } finally {\n                context.shutdown();\n                ConfigurationManager.getConfigInstance().clear();\n            }\n        }\n\n        @Test\n        public void testSecondary() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                ConfigurationManager.getConfigInstance().setProperty(\"primarySecondary.usePrimary\", false);\n                assertEquals(\"responseFromSecondary-20\", new CommandFacadeWithPrimarySecondary(20).execute());\n            } finally {\n                context.shutdown();\n                ConfigurationManager.getConfigInstance().clear();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandHelloFailure.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport java.util.concurrent.Future;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * Sample {@link HystrixCommand} showing a basic fallback implementation.\n */\npublic class CommandHelloFailure extends HystrixCommand<String> {\n\n    private final String name;\n\n    public CommandHelloFailure(String name) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.name = name;\n    }\n\n    @Override\n    protected String run() {\n        throw new RuntimeException(\"this command always fails\");\n    }\n\n    @Override\n    protected String getFallback() {\n        return \"Hello Failure \" + name + \"!\";\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testSynchronous() {\n            assertEquals(\"Hello Failure World!\", new CommandHelloFailure(\"World\").execute());\n            assertEquals(\"Hello Failure Bob!\", new CommandHelloFailure(\"Bob\").execute());\n        }\n\n        @Test\n        public void testAsynchronous1() throws Exception {\n            assertEquals(\"Hello Failure World!\", new CommandHelloFailure(\"World\").queue().get());\n            assertEquals(\"Hello Failure Bob!\", new CommandHelloFailure(\"Bob\").queue().get());\n        }\n\n        @Test\n        public void testAsynchronous2() throws Exception {\n\n            Future<String> fWorld = new CommandHelloFailure(\"World\").queue();\n            Future<String> fBob = new CommandHelloFailure(\"Bob\").queue();\n\n            assertEquals(\"Hello Failure World!\", fWorld.get());\n            assertEquals(\"Hello Failure Bob!\", fBob.get());\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandHelloWorld.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport java.util.concurrent.Future;\n\nimport org.junit.Test;\n\nimport rx.Observable;\nimport rx.Observer;\nimport rx.functions.Action1;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * The obligatory \"Hello World!\" showing a simple implementation of a {@link HystrixCommand}.\n */\npublic class CommandHelloWorld extends HystrixCommand<String> {\n\n    private final String name;\n\n    public CommandHelloWorld(String name) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.name = name;\n    }\n\n    @Override\n    protected String run() {\n        return \"Hello \" + name + \"!\";\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testSynchronous() {\n            assertEquals(\"Hello World!\", new CommandHelloWorld(\"World\").execute());\n            assertEquals(\"Hello Bob!\", new CommandHelloWorld(\"Bob\").execute());\n        }\n\n        @Test\n        public void testAsynchronous1() throws Exception {\n            assertEquals(\"Hello World!\", new CommandHelloWorld(\"World\").queue().get());\n            assertEquals(\"Hello Bob!\", new CommandHelloWorld(\"Bob\").queue().get());\n        }\n\n        @Test\n        public void testAsynchronous2() throws Exception {\n\n            Future<String> fWorld = new CommandHelloWorld(\"World\").queue();\n            Future<String> fBob = new CommandHelloWorld(\"Bob\").queue();\n\n            assertEquals(\"Hello World!\", fWorld.get());\n            assertEquals(\"Hello Bob!\", fBob.get());\n        }\n\n        @Test\n        public void testObservable() throws Exception {\n\n            Observable<String> fWorld = new CommandHelloWorld(\"World\").observe();\n            Observable<String> fBob = new CommandHelloWorld(\"Bob\").observe();\n\n            // blocking\n            assertEquals(\"Hello World!\", fWorld.toBlocking().single());\n            assertEquals(\"Hello Bob!\", fBob.toBlocking().single());\n\n            // non-blocking \n            // - this is a verbose anonymous inner-class approach and doesn't do assertions\n            fWorld.subscribe(new Observer<String>() {\n\n                @Override\n                public void onCompleted() {\n                    // nothing needed here\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    e.printStackTrace();\n                }\n\n                @Override\n                public void onNext(String v) {\n                    System.out.println(\"onNext: \" + v);\n                }\n\n            });\n\n            // non-blocking\n            // - also verbose anonymous inner-class\n            // - ignore errors and onCompleted signal\n            fBob.subscribe(new Action1<String>() {\n\n                @Override\n                public void call(String v) {\n                    System.out.println(\"onNext: \" + v);\n                }\n\n            });\n\n            // non-blocking\n            // - using closures in Java 8 would look like this:\n            \n            //            fWorld.subscribe((v) -> {\n            //                System.out.println(\"onNext: \" + v);\n            //            })\n            \n            // - or while also including error handling\n            \n            //            fWorld.subscribe((v) -> {\n            //                System.out.println(\"onNext: \" + v);\n            //            }, (exception) -> {\n            //                exception.printStackTrace();\n            //            })\n            \n            // More information about Observable can be found at https://github.com/Netflix/RxJava/wiki/How-To-Use\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandThatFailsFast.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\n/**\n * Sample {@link HystrixCommand} that does not have a fallback implemented\n * so will \"fail fast\" when failures, rejections, short-circuiting etc occur.\n */\npublic class CommandThatFailsFast extends HystrixCommand<String> {\n\n    private final boolean throwException;\n\n    public CommandThatFailsFast(boolean throwException) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.throwException = throwException;\n    }\n\n    @Override\n    protected String run() {\n        if (throwException) {\n            throw new RuntimeException(\"failure from CommandThatFailsFast\");\n        } else {\n            return \"success\";\n        }\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testSuccess() {\n            assertEquals(\"success\", new CommandThatFailsFast(false).execute());\n        }\n\n        @Test\n        public void testFailure() {\n            try {\n                new CommandThatFailsFast(true).execute();\n                fail(\"we should have thrown an exception\");\n            } catch (HystrixRuntimeException e) {\n                assertEquals(\"failure from CommandThatFailsFast\", e.getCause().getMessage());\n                e.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandThatFailsSilently.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.exception.HystrixRuntimeException;\n\n/**\n * Sample {@link HystrixCommand} that has a fallback implemented\n * that will \"fail silent\" when failures, rejections, short-circuiting etc occur\n * by returning an empty List.\n */\npublic class CommandThatFailsSilently extends HystrixCommand<List<String>> {\n\n    private final boolean throwException;\n\n    public CommandThatFailsSilently(boolean throwException) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.throwException = throwException;\n    }\n\n    @Override\n    protected List<String> run() {\n        if (throwException) {\n            throw new RuntimeException(\"failure from CommandThatFailsFast\");\n        } else {\n            ArrayList<String> values = new ArrayList<String>();\n            values.add(\"success\");\n            return values;\n        }\n    }\n\n    @Override\n    protected List<String> getFallback() {\n        return Collections.emptyList();\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testSuccess() {\n            assertEquals(\"success\", new CommandThatFailsSilently(false).execute().get(0));\n        }\n\n        @Test\n        public void testFailure() {\n            try {\n                assertEquals(0, new CommandThatFailsSilently(true).execute().size());\n            } catch (HystrixRuntimeException e) {\n                fail(\"we should not get an exception as we fail silently with a fallback\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandUsingRequestCache.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Sample {@link HystrixCommand} showing how implementing the {@link #getCacheKey()} method\n * enables request caching for eliminating duplicate calls within the same request context.\n */\npublic class CommandUsingRequestCache extends HystrixCommand<Boolean> {\n\n    private final int value;\n\n    protected CommandUsingRequestCache(int value) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.value = value;\n    }\n\n    @Override\n    protected Boolean run() {\n        return value == 0 || value % 2 == 0;\n    }\n\n    @Override\n    protected String getCacheKey() {\n        return String.valueOf(value);\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void testWithoutCacheHits() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                assertTrue(new CommandUsingRequestCache(2).execute());\n                assertFalse(new CommandUsingRequestCache(1).execute());\n                assertTrue(new CommandUsingRequestCache(0).execute());\n                assertTrue(new CommandUsingRequestCache(58672).execute());\n            } finally {\n                context.shutdown();\n            }\n        }\n\n        @Test\n        public void testWithCacheHits() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);\n                CommandUsingRequestCache command2b = new CommandUsingRequestCache(2);\n\n                assertTrue(command2a.execute());\n                // this is the first time we've executed this command with the value of \"2\" so it should not be from cache\n                assertFalse(command2a.isResponseFromCache());\n\n                assertTrue(command2b.execute());\n                // this is the second time we've executed this command with the same value so it should return from cache\n                assertTrue(command2b.isResponseFromCache());\n            } finally {\n                context.shutdown();\n            }\n\n            // start a new request context\n            context = HystrixRequestContext.initializeContext();\n            try {\n                CommandUsingRequestCache command3b = new CommandUsingRequestCache(2);\n                assertTrue(command3b.execute());\n                // this is a new request context so this should not come from cache\n                assertFalse(command3b.isResponseFromCache());\n            } finally {\n                context.shutdown();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandUsingRequestCacheInvalidation.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixRequestCache;\nimport com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Example {@link HystrixCommand} implementation for handling the get-set-get use case within\n * a single request context so that the \"set\" can invalidate the cached \"get\".\n */\npublic class CommandUsingRequestCacheInvalidation {\n\n    /* represents a remote data store */\n    private static volatile String prefixStoredOnRemoteDataStore = \"ValueBeforeSet_\";\n\n    public static class GetterCommand extends HystrixCommand<String> {\n\n        private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey(\"GetterCommand\");\n        private final int id;\n\n        public GetterCommand(int id) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"GetSetGet\"))\n                    .andCommandKey(GETTER_KEY));\n            this.id = id;\n        }\n\n        @Override\n        protected String run() {\n            return prefixStoredOnRemoteDataStore + id;\n        }\n\n        @Override\n        protected String getCacheKey() {\n            return String.valueOf(id);\n        }\n\n        /**\n         * Allow the cache to be flushed for this object.\n         * \n         * @param id\n         *            argument that would normally be passed to the command\n         */\n        public static void flushCache(int id) {\n            HystrixRequestCache.getInstance(GETTER_KEY,\n                    HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));\n        }\n\n    }\n\n    public static class SetterCommand extends HystrixCommand<Void> {\n\n        private final int id;\n        private final String prefix;\n\n        public SetterCommand(int id, String prefix) {\n            super(HystrixCommandGroupKey.Factory.asKey(\"GetSetGet\"));\n            this.id = id;\n            this.prefix = prefix;\n        }\n\n        @Override\n        protected Void run() {\n            // persist the value against the datastore\n            prefixStoredOnRemoteDataStore = prefix;\n            // flush the cache\n            GetterCommand.flushCache(id);\n            // no return value\n            return null;\n        }\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void getGetSetGet() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                assertEquals(\"ValueBeforeSet_1\", new GetterCommand(1).execute());\n                GetterCommand commandAgainstCache = new GetterCommand(1);\n                assertEquals(\"ValueBeforeSet_1\", commandAgainstCache.execute());\n                // confirm it executed against cache the second time\n                assertTrue(commandAgainstCache.isResponseFromCache());\n                // set the new value\n                new SetterCommand(1, \"ValueAfterSet_\").execute();\n                // fetch it again\n                GetterCommand commandAfterSet = new GetterCommand(1);\n                // the getter should return with the new prefix, not the value from cache\n                assertFalse(commandAfterSet.isResponseFromCache());\n                assertEquals(\"ValueAfterSet_1\", commandAfterSet.execute());\n            } finally {\n                context.shutdown();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandUsingSemaphoreIsolation.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;\n\n/**\n * Example of {@link HystrixCommand} defaulting to use a semaphore isolation strategy\n * when its run() method will not perform network traffic.\n */\npublic class CommandUsingSemaphoreIsolation extends HystrixCommand<String> {\n\n    private final int id;\n\n    public CommandUsingSemaphoreIsolation(int id) {\n        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"))\n                // since we're doing work in the run() method that doesn't involve network traffic\n                // and executes very fast with low risk we choose SEMAPHORE isolation\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()\n                        .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));\n        this.id = id;\n    }\n\n    @Override\n    protected String run() {\n        // a real implementation would retrieve data from in memory data structure\n        // or some other similar non-network involved work\n        return \"ValueFromHashMap_\" + id;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandWithFallbackViaNetwork.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Sample {@link HystrixCommand} that implements fallback logic that requires\n * network traffic and thus executes another {@link HystrixCommand} from the {@link #getFallback()} method.\n * <p>\n * Note also that the fallback command uses a separate thread-pool as well even though\n * it's in the same command group.\n * <p>\n * It needs to be on a separate thread-pool otherwise the first command could saturate it\n * and the fallback command never have a chance to execute.\n */\npublic class CommandWithFallbackViaNetwork extends HystrixCommand<String> {\n    private final int id;\n\n    protected CommandWithFallbackViaNetwork(int id) {\n        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"RemoteServiceX\"))\n                .andCommandKey(HystrixCommandKey.Factory.asKey(\"GetValueCommand\")));\n        this.id = id;\n    }\n\n    @Override\n    protected String run() {\n        //        RemoteServiceXClient.getValue(id);\n        throw new RuntimeException(\"force failure for example\");\n    }\n\n    @Override\n    protected String getFallback() {\n        return new FallbackViaNetwork(id).execute();\n    }\n\n    private static class FallbackViaNetwork extends HystrixCommand<String> {\n        private final int id;\n\n        public FallbackViaNetwork(int id) {\n            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"RemoteServiceX\"))\n                    .andCommandKey(HystrixCommandKey.Factory.asKey(\"GetValueFallbackCommand\"))\n                    // use a different threadpool for the fallback command\n                    // so saturating the RemoteServiceX pool won't prevent\n                    // fallbacks from executing\n                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(\"RemoteServiceXFallback\")));\n            this.id = id;\n        }\n\n        @Override\n        protected String run() {\n            //            MemCacheClient.getValue(id);\n            throw new RuntimeException(\"the fallback also failed\");\n        }\n\n        @Override\n        protected String getFallback() {\n            // the fallback also failed\n            // so this fallback-of-a-fallback will \n            // fail silently and return null\n            return null;\n        }\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void test() {\n            HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            try {\n                assertEquals(null, new CommandWithFallbackViaNetwork(1).execute());\n\n                HystrixInvokableInfo<?> command1 = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[2])[0];\n                assertEquals(\"GetValueCommand\", command1.getCommandKey().name());\n                assertTrue(command1.getExecutionEvents().contains(HystrixEventType.FAILURE));\n\n                HystrixInvokableInfo<?> command2 = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo<?>[2])[1];\n                assertEquals(\"GetValueFallbackCommand\", command2.getCommandKey().name());\n                assertTrue(command2.getExecutionEvents().contains(HystrixEventType.FAILURE));\n            } finally {\n                context.shutdown();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/CommandWithStubbedFallback.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.examples.basic.CommandWithStubbedFallback.UserAccount;\n\n/**\n * Sample {@link HystrixCommand} that implements a fallback that returns an object\n * combining defaults and injected values from elsewhere in the system (such as\n * HTTP request headers, arguments and cookies or other services previously executed).\n */\npublic class CommandWithStubbedFallback extends HystrixCommand<UserAccount> {\n\n    private final int customerId;\n    private final String countryCodeFromGeoLookup;\n\n    /**\n     * @param customerId\n     *            The customerID to retrieve UserAccount for\n     * @param countryCodeFromGeoLookup\n     *            The default country code from the HTTP request geo code lookup used for fallback.\n     */\n    protected CommandWithStubbedFallback(int customerId, String countryCodeFromGeoLookup) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"ExampleGroup\"));\n        this.customerId = customerId;\n        this.countryCodeFromGeoLookup = countryCodeFromGeoLookup;\n    }\n\n    @Override\n    protected UserAccount run() {\n        // fetch UserAccount from remote service\n        //        return UserAccountClient.getAccount(customerId);\n        throw new RuntimeException(\"forcing failure for example\");\n    }\n\n    @Override\n    protected UserAccount getFallback() {\n        /**\n         * Return stubbed fallback with some static defaults, placeholders,\n         * and an injected value 'countryCodeFromGeoLookup' that we'll use\n         * instead of what we would have retrieved from the remote service.\n         */\n        return new UserAccount(customerId, \"Unknown Name\",\n                countryCodeFromGeoLookup, true, true, false);\n    }\n\n    public static class UserAccount {\n        private final int customerId;\n        private final String name;\n        private final String countryCode;\n        private final boolean isFeatureXPermitted;\n        private final boolean isFeatureYPermitted;\n        private final boolean isFeatureZPermitted;\n\n        UserAccount(int customerId, String name, String countryCode,\n                boolean isFeatureXPermitted,\n                boolean isFeatureYPermitted,\n                boolean isFeatureZPermitted) {\n            this.customerId = customerId;\n            this.name = name;\n            this.countryCode = countryCode;\n            this.isFeatureXPermitted = isFeatureXPermitted;\n            this.isFeatureYPermitted = isFeatureYPermitted;\n            this.isFeatureZPermitted = isFeatureZPermitted;\n        }\n    }\n\n    public static class UnitTest {\n\n        @Test\n        public void test() {\n            CommandWithStubbedFallback command = new CommandWithStubbedFallback(1234, \"ca\");\n            UserAccount account = command.execute();\n            assertTrue(command.isFailedExecution());\n            assertTrue(command.isResponseFromFallback());\n            assertEquals(1234, account.customerId);\n            assertEquals(\"ca\", account.countryCode);\n            assertEquals(true, account.isFeatureXPermitted);\n            assertEquals(true, account.isFeatureYPermitted);\n            assertEquals(false, account.isFeatureZPermitted);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/ObservableCollapserGetWordForNumber.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport rx.Observable;\nimport rx.functions.Func0;\nimport rx.functions.Func1;\nimport rx.observers.TestSubscriber;\nimport rx.schedulers.Schedulers;\n\nimport com.netflix.hystrix.HystrixCollapser.CollapsedRequest;\nimport com.netflix.hystrix.HystrixObservableCollapser;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.examples.basic.ObservableCommandNumbersToWords.NumberWord;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Example that uses {@link HystrixObservableCollapser} to batch multiple {@link ObservableCommandNumbersToWords} requests.\n *\n * @author Patrick Ruhkopf\n */\npublic class ObservableCollapserGetWordForNumber extends HystrixObservableCollapser<Integer, NumberWord, String, Integer>\n{\n\tprivate final Integer number;\n\n\tprivate final static AtomicInteger counter = new AtomicInteger();\n\n\tpublic static void resetCmdCounter()\n\t{\n\t\tcounter.set(0);\n\t}\n\n\tpublic static int getCmdCount()\n\t{\n\t\treturn counter.get();\n\t}\n\n\tpublic ObservableCollapserGetWordForNumber(final Integer number)\n\t{\n\t\tthis.number = number;\n\t}\n\n\t@Override\n\tpublic Integer getRequestArgument()\n\t{\n\t\treturn number;\n\t}\n\n\t@SuppressWarnings(\"boxing\")\n\t@Override\n\tprotected HystrixObservableCommand<NumberWord> createCommand(final Collection<CollapsedRequest<String, Integer>> requests)\n\t{\n\t\tfinal int count = counter.incrementAndGet();\n\t\tSystem.out.println(\"Creating batch for \" + requests.size() + \" requests. Total invocations so far: \" + count);\n\n\t\tfinal List<Integer> numbers = new ArrayList<Integer>();\n\t\tfor (final CollapsedRequest<String, Integer> request : requests)\n\t\t{\n\t\t\tnumbers.add(request.getArgument());\n\t\t}\n\n\t\treturn new ObservableCommandNumbersToWords(numbers);\n\t}\n\n\t@Override\n\tprotected Func1<NumberWord, Integer> getBatchReturnTypeKeySelector()\n\t{\n\t\t// Java 8: (final NumberWord nw) -> nw.getNumber();\n\n\t\treturn new Func1<NumberWord, Integer>()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic Integer call(final NumberWord nw)\n\t\t\t{\n\t\t\t\treturn nw.getNumber();\n\t\t\t}\n\t\t};\n\t}\n\n\t@Override\n\tprotected Func1<Integer, Integer> getRequestArgumentKeySelector()\n\t{\n\t\t// Java 8: return (final Integer no) -> no;\n\n\t\treturn new Func1<Integer, Integer>()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic Integer call(final Integer no)\n\t\t\t{\n\t\t\t\treturn no;\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Override\n\tprotected Func1<NumberWord, String> getBatchReturnTypeToResponseTypeMapper()\n\t{\n\t\t// Java 8: return (final NumberWord nw) -> nw.getWord();\n\n\t\treturn new Func1<NumberWord, String>()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic String call(final NumberWord nw)\n\t\t\t{\n\t\t\t\treturn nw.getWord();\n\t\t\t}\n\t\t};\n\t}\n\n\t@Override\n\tprotected void onMissingResponse(final CollapsedRequest<String, Integer> request)\n\t{\n\t\trequest.setException(new Exception(\"No word\"));\n\t}\n\n\tpublic static class ObservableCollapserGetWordForNumberTest\n\t{\n\t\tprivate HystrixRequestContext ctx;\n\n\t\t@Before\n\t\tpublic void before()\n\t\t{\n\t\t\tctx = HystrixRequestContext.initializeContext();\n\t\t\tObservableCollapserGetWordForNumber.resetCmdCounter();\n\t\t}\n\n\t\t@After\n\t\tpublic void after()\n\t\t{\n\t\t\tSystem.out.println(HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n\t\t\tctx.shutdown();\n\t\t}\n\n\t\t/**\n\t\t * Example where we subscribe without using a specific scheduler. That means we run the actions on the same thread.\n\t\t */\n\t\t@Test\n\t\tpublic void shouldCollapseRequestsSync()\n\t\t{\n\t\t\tfinal int noOfRequests = 10;\n\t\t\tfinal Map<Integer, TestSubscriber<String>> subscribersByNumber = new HashMap<Integer, TestSubscriber<String>>(\n\t\t\t\t\tnoOfRequests);\n\n\t\t\tTestSubscriber<String> subscriber;\n\t\t\tfor (int number = 0; number < noOfRequests; number++)\n\t\t\t{\n\t\t\t\tsubscriber = new TestSubscriber<String>();\n\t\t\t\tnew ObservableCollapserGetWordForNumber(number).toObservable().subscribe(subscriber);\n\t\t\t\tsubscribersByNumber.put(number, subscriber);\n\n\t\t\t\t// wait a little bit after running half of the requests so that we don't collapse all of them into one batch\n\t\t\t\t// TODO this can probably be improved by using a test scheduler\n\t\t\t\tif (number == noOfRequests / 2)\n\t\t\t\t\tsleep(1000);\n\n\t\t\t}\n\n\t\t\tassertThat(subscribersByNumber.size(), is(noOfRequests));\n\t\t\tfor (final Entry<Integer, TestSubscriber<String>> subscriberByNumber : subscribersByNumber.entrySet())\n\t\t\t{\n\t\t\t\tsubscriber = subscriberByNumber.getValue();\n\t\t\t\tsubscriber.awaitTerminalEvent(10, TimeUnit.SECONDS);\n\n\t\t\t\tassertThat(subscriber.getOnErrorEvents().toString(), subscriber.getOnErrorEvents().size(), is(0));\n\t\t\t\tassertThat(subscriber.getOnNextEvents().size(), is(1));\n\n\t\t\t\tfinal String word = subscriber.getOnNextEvents().get(0);\n\t\t\t\tSystem.out.println(\"Translated \" + subscriberByNumber.getKey() + \" to \" + word);\n\t\t\t\tassertThat(word, equalTo(numberToWord(subscriberByNumber.getKey())));\n\t\t\t}\n\n\t\t\tassertTrue(ObservableCollapserGetWordForNumber.getCmdCount() > 1);\n\t\t\tassertTrue(ObservableCollapserGetWordForNumber.getCmdCount() < noOfRequests);\n\t\t}\n\n\t\t/**\n\t\t * Example where we subscribe on the computation scheduler. For this we need the {@link HystrixContextScheduler}, that\n\t\t * passes the {@link HystrixRequestContext} to the thread that runs the action.\n\t\t */\n\t\t@Test\n\t\tpublic void shouldCollapseRequestsAsync()\n\t\t{\n\t\t\tfinal HystrixContextScheduler contextAwareScheduler = new HystrixContextScheduler(Schedulers.computation());\n\n\t\t\tfinal int noOfRequests = 10;\n\t\t\tfinal Map<Integer, TestSubscriber<String>> subscribersByNumber = new HashMap<Integer, TestSubscriber<String>>(\n\t\t\t\t\tnoOfRequests);\n\n\t\t\tTestSubscriber<String> subscriber;\n\t\t\tfor (int number = 0; number < noOfRequests; number++)\n\t\t\t{\n\t\t\t\tsubscriber = new TestSubscriber<String>();\n\t\t\t\tfinal int finalNumber = number;\n\n\t\t\t\t// defer and subscribe on specific scheduler\n\t\t\t\tObservable.defer(new Func0<Observable<String>>()\n\t\t\t\t{\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Observable<String> call()\n\t\t\t\t\t{\n\t\t\t\t\t\treturn new ObservableCollapserGetWordForNumber(finalNumber).toObservable();\n\t\t\t\t\t}\n\t\t\t\t}).subscribeOn(contextAwareScheduler).subscribe(subscriber);\n\n\t\t\t\tsubscribersByNumber.put(number, subscriber);\n\n\t\t\t\t// wait a little bit after running half of the requests so that we don't collapse all of them into one batch\n\t\t\t\t// TODO this can probably be improved by using a test scheduler\n\t\t\t\tif (number == noOfRequests / 2)\n\t\t\t\t\tsleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(subscribersByNumber.size(), is(noOfRequests));\n\t\t\tfor (final Entry<Integer, TestSubscriber<String>> subscriberByNumber : subscribersByNumber.entrySet())\n\t\t\t{\n\t\t\t\tsubscriber = subscriberByNumber.getValue();\n\t\t\t\tsubscriber.awaitTerminalEvent(10, TimeUnit.SECONDS);\n\n\t\t\t\tassertThat(subscriber.getOnErrorEvents().toString(), subscriber.getOnErrorEvents().size(), is(0));\n\t\t\t\tassertThat(subscriber.getOnNextEvents().size(), is(1));\n\n\t\t\t\tfinal String word = subscriber.getOnNextEvents().get(0);\n\t\t\t\tSystem.out.println(\"Translated \" + subscriberByNumber.getKey() + \" to \" + word);\n\t\t\t\tassertThat(word, equalTo(numberToWord(subscriberByNumber.getKey())));\n\t\t\t}\n\n\t\t\tassertTrue(ObservableCollapserGetWordForNumber.getCmdCount() > 1);\n\t\t\tassertTrue(ObservableCollapserGetWordForNumber.getCmdCount() < noOfRequests);\n\t\t}\n\n\t\t@Test\n\t\tpublic void shouldCollapseSameRequests()\n\t\t{\n\t\t\t//given\n\t\t\tfinal HystrixContextScheduler contextAwareScheduler = new HystrixContextScheduler(Schedulers.computation());\n\n\t\t\t//when\n\t\t\tTestSubscriber<String> subscriber1 = getWordForNumber(contextAwareScheduler, 0);\n\t\t\tTestSubscriber<String> subscriber2 = getWordForNumber(contextAwareScheduler, 0);\n\n\t\t\t//then\n\t\t\tsubscriberReceived(subscriber1, 0);\n\t\t\tsubscriberReceived(subscriber2, 0);\n\t\t}\n\n\t\tprivate TestSubscriber<String> getWordForNumber(HystrixContextScheduler contextAwareScheduler, final int number) {\n\t\t\tfinal TestSubscriber<String> subscriber = new TestSubscriber<String>();\n\t\t\tObservable.defer(new Func0<Observable<String>>()\n\t\t\t{\n\t\t\t\t@Override\n\t\t\t\tpublic Observable<String> call()\n\t\t\t\t{\n\t\t\t\t\treturn new ObservableCollapserGetWordForNumber(number).toObservable();\n\t\t\t\t}\n\t\t\t}).subscribeOn(contextAwareScheduler).subscribe(subscriber);\n\t\t\treturn subscriber;\n\t\t}\n\n\t\tprivate void subscriberReceived(TestSubscriber<String> subscriber, int number) {\n\t\t\tsubscriber.awaitTerminalEvent(10, TimeUnit.SECONDS);\n\t\t\tassertThat(subscriber.getOnErrorEvents().toString(), subscriber.getOnErrorEvents().size(), is(0));\n\t\t\tassertThat(subscriber.getOnNextEvents().size(), is(1));\n\t\t\tassertThat(subscriber.getOnNextEvents().get(0), equalTo(numberToWord(number)));\n\t\t}\n\n\t\tprivate String numberToWord(final int number)\n\t\t{\n\t\t\treturn ObservableCommandNumbersToWords.dict.get(number);\n\t\t}\n\n\t\tprivate void sleep(final long ms)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t\tcatch (final InterruptedException e)\n\t\t\t{\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/basic/ObservableCommandNumbersToWords.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.basic;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport rx.Observable;\nimport rx.functions.Func1;\n\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixObservableCommand;\nimport com.netflix.hystrix.examples.basic.ObservableCommandNumbersToWords.NumberWord;\n\n/**\n * A simple Hystrix Observable command that translates a number (<code>Integer</code>) into an English text.\n */\nclass ObservableCommandNumbersToWords extends HystrixObservableCommand<NumberWord>\n{\n\tprivate final List<Integer> numbers;\n\n\t// in the real world you'd probably want to replace this very simple code by using ICU or similar\n\tstatic Map<Integer, String> dict = new HashMap<Integer, String>(11);\n\tstatic\n\t{\n\t\tdict.put(0, \"zero\");\n\t\tdict.put(1, \"one\");\n\t\tdict.put(2, \"two\");\n\t\tdict.put(3, \"three\");\n\t\tdict.put(4, \"four\");\n\t\tdict.put(5, \"five\");\n\t\tdict.put(6, \"six\");\n\t\tdict.put(7, \"seven\");\n\t\tdict.put(8, \"eight\");\n\t\tdict.put(9, \"nine\");\n\t\tdict.put(10, \"ten\");\n\t}\n\n\tpublic ObservableCommandNumbersToWords(final List<Integer> numbers)\n\t{\n\t\tsuper(HystrixCommandGroupKey.Factory.asKey(ObservableCommandNumbersToWords.class.getName()));\n\t\tthis.numbers = numbers;\n\t}\n\n\t@Override\n\tprotected Observable<NumberWord> construct()\n\t{\n\t\treturn Observable.from(numbers).map(new Func1<Integer, NumberWord>()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic NumberWord call(final Integer number)\n\t\t\t{\n\t\t\t\treturn new NumberWord(number, dict.get(number));\n\t\t\t}\n\n\t\t});\n\t}\n\n\tstatic class NumberWord\n\t{\n\t\tprivate final Integer number;\n\t\tprivate final String word;\n\n\t\tpublic NumberWord(final Integer number, final String word)\n\t\t{\n\t\t\tsuper();\n\t\t\tthis.number = number;\n\t\t\tthis.word = word;\n\t\t}\n\n\t\tpublic Integer getNumber()\n\t\t{\n\t\t\treturn number;\n\t\t}\n\n\t\tpublic String getWord()\n\t\t{\n\t\t\treturn word;\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/CreditCardAuthorizationResult.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\n/**\n * POJO for holding the result of a CreditCardAuthorization\n */\npublic class CreditCardAuthorizationResult {\n\n    public static CreditCardAuthorizationResult createSuccessResponse(String transactionID, String authorizationCode) {\n        return new CreditCardAuthorizationResult(true, transactionID, authorizationCode, false);\n    }\n\n    public static CreditCardAuthorizationResult createDuplicateSuccessResponse(String transactionID, String authorizationCode) {\n        return new CreditCardAuthorizationResult(true, transactionID, authorizationCode, true);\n    }\n\n    public static CreditCardAuthorizationResult createFailedResponse(String message) {\n        return new CreditCardAuthorizationResult(false, message, null, false);\n    }\n\n    private final boolean success;\n    private final boolean isDuplicate;\n    private final String authorizationCode;\n    private final String transactionID;\n    private final String errorMessage;\n\n    /**\n     * Private constructor that normally would be a horrible API as it re-uses different arguments for different state.\n     * \n     * @param success\n     * @param value\n     * @param isResponseDuplicate\n     *            boolean whether the response is the result of a duplicate transaction returning a previously submitted transaction result\n     *            <p>\n     *            This is for handling the idempotent double-posting scenario, such as retries after timeouts.\n     */\n    private CreditCardAuthorizationResult(boolean success, String value, String value2, boolean isResponseDuplicate) {\n        this.success = success;\n        this.isDuplicate = isResponseDuplicate;\n        if (success) {\n            this.transactionID = value;\n            this.authorizationCode = value2;\n            this.errorMessage = null;\n        } else {\n            this.transactionID = null;\n            this.errorMessage = value;\n            this.authorizationCode = null;\n        }\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    /**\n     * Whether this result was a duplicate transaction.\n     * \n     * @return boolean\n     */\n    public boolean isDuplicateTransaction() {\n        return isDuplicate;\n    }\n\n    /**\n     * If <code>isSuccess() == true</code> this will return the authorization code.\n     * <p>\n     * If <code>isSuccess() == false</code> this will return NULL.\n     * \n     * @return String\n     */\n    public String getAuthorizationCode() {\n        return authorizationCode;\n    }\n\n    /**\n     * If <code>isSuccess() == true</code> this will return the transaction ID.\n     * <p>\n     * If <code>isSuccess() == false</code> this will return NULL.\n     * \n     * @return String\n     */\n    public String getTransactionID() {\n        return transactionID;\n    }\n\n    /**\n     * If <code>isSuccess() == false</code> this will return the error message.\n     * <p>\n     * If <code>isSuccess() == true</code> this will return NULL.\n     * \n     * @return String\n     */\n    public String getErrorMessage() {\n        return errorMessage;\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/CreditCardCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport java.math.BigDecimal;\nimport java.net.HttpCookie;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandProperties;\n\n/**\n * This class was originally taken from a functional example using the Authorize.net API\n * but was modified for this example to use mock classes so that the real API does not need\n * to be depended upon and so that a backend account with Authorize.net is not needed.\n */\n// import net.authorize.Environment;\n// import net.authorize.TransactionType;\n// import net.authorize.aim.Result;\n// import net.authorize.aim.Transaction;\n\n/**\n * HystrixCommand for submitting credit card payments.\n * <p>\n * No fallback implemented as a credit card failure must result in an error as no logical fallback exists.\n * <p>\n * This implementation originated from a functional HystrixCommand wrapper around an Authorize.net API.\n * <p>\n * The original used the Authorize.net 'duplicate window' setting to ensure an Order could be submitted multiple times\n * and it would behave idempotently so that it would not result in duplicate transactions and each would return a successful\n * response as if it was the first-and-only execution.\n * <p>\n * This idempotence (within the duplicate window time frame set to multiple hours) allows for clients that\n * experience timeouts and failures to confidently retry the credit card transaction without fear of duplicate\n * credit card charges.\n * <p>\n * This in turn allows the HystrixCommand to be configured for reasonable timeouts and isolation rather than\n * letting it go 10+ seconds hoping for success when latency occurs.\n * <p>\n * In this example, the timeout is set to 3,000ms as normal behavior typically saw a credit card transaction taking around 1300ms\n * and in this case it's better to wait longer and try to succeed as the result is a user error.\n * <p>\n * We do not want to wait the 10,000-20,000ms that Authorize.net can default to as that would allow severe resource\n * saturation under high volume traffic when latency spikes.\n */\npublic class CreditCardCommand extends HystrixCommand<CreditCardAuthorizationResult> {\n    private final static AuthorizeNetGateway DEFAULT_GATEWAY = new AuthorizeNetGateway();\n\n    private final AuthorizeNetGateway gateway;\n    private final Order order;\n    private final PaymentInformation payment;\n    private final BigDecimal amount;\n\n    /**\n     * A HystrixCommand implementation accepts arguments into the constructor which are then accessible\n     * to the <code>run()</code> method when it executes.\n     * \n     * @param order\n     * @param payment\n     * @param amount\n     */\n    public CreditCardCommand(Order order, PaymentInformation payment, BigDecimal amount) {\n        this(DEFAULT_GATEWAY, order, payment, amount);\n    }\n\n    private CreditCardCommand(AuthorizeNetGateway gateway, Order order, PaymentInformation payment, BigDecimal amount) {\n        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"CreditCard\"))\n                // defaulting to a fairly long timeout value because failing a credit card transaction is a bad user experience and 'costly' to re-attempt\n                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(3000)));\n        this.gateway = gateway;\n        this.order = order;\n        this.payment = payment;\n        this.amount = amount;\n    }\n\n    /**\n     * Actual work of submitting the credit card authorization occurs within this <code>HystrixCommand.run()</code> method.\n     */\n    @Override\n    protected CreditCardAuthorizationResult run() {\n        // Simulate transitive dependency from CreditCardCommand to GetUserAccountCommand.\n        // UserAccount could be injected into this command as an argument (and that would be more accurate)\n        // but often in large codebase that ends up not happening and each library fetches common data\n        // such as user information directly such as this example.\n        UserAccount user = new GetUserAccountCommand(new HttpCookie(\"mockKey\", \"mockValueFromHttpRequest\")).execute();\n        if (user.getAccountType() == 1) {\n            // do something\n        } else {\n            // do something else\n        }\n\n        // perform credit card transaction\n        Result<Transaction> result = gateway.submit(payment.getCreditCardNumber(),\n                String.valueOf(payment.getExpirationMonth()),\n                String.valueOf(payment.getExpirationYear()),\n                TransactionType.AUTH_CAPTURE, amount, order);\n\n        if (result.isApproved()) {\n            return CreditCardAuthorizationResult.createSuccessResponse(result.getTarget().getTransactionId(), result.getTarget().getAuthorizationCode());\n        } else if (result.isDeclined()) {\n            return CreditCardAuthorizationResult.createFailedResponse(result.getReasonResponseCode() + \" : \" + result.getResponseText());\n        } else {\n            // check for duplicate transaction\n            if (result.getReasonResponseCode().getResponseReasonCode() == 11) {\n                if (result.getTarget().getAuthorizationCode() != null) {\n                    // We will treat this as a success as this is telling us we have a successful authorization code\n                    // just that we attempted to re-post it again during the 'duplicateWindow' time period.\n                    // This is part of the idempotent behavior we require so that we can safely timeout and/or fail and allow\n                    // client applications to re-attempt submitting a credit card transaction for the same order again.\n                    // In those cases if the client saw a failure but the transaction actually succeeded, this will capture the\n                    // duplicate response and behave to the client as a success.\n                    return CreditCardAuthorizationResult.createDuplicateSuccessResponse(result.getTarget().getTransactionId(), result.getTarget().getAuthorizationCode());\n                }\n            }\n            // handle all other errors\n            return CreditCardAuthorizationResult.createFailedResponse(result.getReasonResponseCode() + \" : \" + result.getResponseText());\n            /**\n             * NOTE that in this use case we do not throw an exception for an \"error\" as this type of error from the service is not a system error,\n             * but a legitimate usage problem successfully delivered back from the service.\n             * \n             * Unexpected errors will be allowed to throw RuntimeExceptions.\n             * \n             * The HystrixBadRequestException could potentially be used here, but with such a complex set of errors and reason codes\n             * it was chosen to stick with the response object approach rather than using an exception.\n             */\n        }\n    }\n\n    /*\n     * The following inner classes are all mocks based on the Authorize.net API that this class originally used.\n     * \n     * They are statically mocked in this example to demonstrate how Hystrix might behave when wrapping this type of call.\n     */\n\n    public static class AuthorizeNetGateway {\n        public AuthorizeNetGateway() {\n\n        }\n\n        public Result<Transaction> submit(String creditCardNumber, String expirationMonth, String expirationYear, TransactionType authCapture, BigDecimal amount, Order order) {\n            /* simulate varying length of time 800-1500ms which is typical for a credit card transaction */\n            try {\n                Thread.sleep((int) (Math.random() * 700) + 800);\n            } catch (InterruptedException e) {\n                // do nothing\n            }\n\n            /* and every once in a while we'll cause it to go longer than 3000ms which will cause the command to timeout */\n            if (Math.random() > 0.99) {\n                try {\n                    Thread.sleep(8000);\n                } catch (InterruptedException e) {\n                    // do nothing\n                }\n            }\n\n            if (Math.random() < 0.8) {\n                return new Result<Transaction>(true);\n            } else {\n                return new Result<Transaction>(false);\n            }\n\n        }\n    }\n\n    public static class Result<T> {\n\n        private final boolean approved;\n\n        public Result(boolean approved) {\n            this.approved = approved;\n        }\n\n        public boolean isApproved() {\n            return approved;\n        }\n\n        public ResponseCode getResponseText() {\n            return null;\n        }\n\n        public Target getTarget() {\n            return new Target();\n        }\n\n        public ResponseCode getReasonResponseCode() {\n            return new ResponseCode();\n        }\n\n        public boolean isDeclined() {\n            return !approved;\n        }\n\n    }\n\n    public static class ResponseCode {\n\n        public int getResponseReasonCode() {\n            return 0;\n        }\n\n    }\n\n    public static class Target {\n\n        public String getTransactionId() {\n            return \"transactionId\";\n        }\n\n        public String getAuthorizationCode() {\n            return \"authorizedCode\";\n        }\n\n    }\n\n    public static class Transaction {\n\n    }\n\n    public static enum TransactionType {\n        AUTH_CAPTURE\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/GetOrderCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * Sample HystrixCommand simulating one that would fetch Order objects from a remote service or database.\n * <p>\n * This fails fast with no fallback and does not use request caching.\n */\npublic class GetOrderCommand extends HystrixCommand<Order> {\n\n    private final int orderId;\n\n    public GetOrderCommand(int orderId) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"Order\"));\n        this.orderId = orderId;\n    }\n\n    @Override\n    protected Order run() {\n        /* simulate performing network call to retrieve order */\n        try {\n            Thread.sleep((int) (Math.random() * 200) + 50);\n        } catch (InterruptedException e) {\n            // do nothing\n        }\n\n        /* fail rarely ... but allow failure as this one has no fallback */\n        if (Math.random() > 0.9999) {\n            throw new RuntimeException(\"random failure loading order over network\");\n        }\n\n        /* latency spike 5% of the time */\n        if (Math.random() > 0.95) {\n            // random latency spike\n            try {\n                Thread.sleep((int) (Math.random() * 300) + 25);\n            } catch (InterruptedException e) {\n                // do nothing\n            }\n        }\n\n        /* success ... create Order with data \"from\" the remote service response */\n        return new Order(orderId);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/GetPaymentInformationCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * Sample HystrixCommand simulating one that would fetch PaymentInformation objects from a remote service or database.\n * <p>\n * This fails fast with no fallback and does not use request caching.\n */\npublic class GetPaymentInformationCommand extends HystrixCommand<PaymentInformation> {\n\n    private final UserAccount user;\n\n    public GetPaymentInformationCommand(UserAccount user) {\n        super(HystrixCommandGroupKey.Factory.asKey(\"PaymentInformation\"));\n        this.user = user;\n    }\n\n    @Override\n    protected PaymentInformation run() {\n        /* simulate performing network call to retrieve order */\n        try {\n            Thread.sleep((int) (Math.random() * 20) + 5);\n        } catch (InterruptedException e) {\n            // do nothing\n        }\n\n        /* fail rarely ... but allow failure */\n        if (Math.random() > 0.9999) {\n            throw new RuntimeException(\"random failure loading payment information over network\");\n        }\n\n        /* latency spike 2% of the time */\n        if (Math.random() > 0.98) {\n            // random latency spike\n            try {\n                Thread.sleep((int) (Math.random() * 100) + 25);\n            } catch (InterruptedException e) {\n                // do nothing\n            }\n        }\n\n        /* success ... create (a very insecure) PaymentInformation with data \"from\" the remote service response */\n        return new PaymentInformation(user, \"4444888833337777\", 12, 15);\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/GetUserAccountCommand.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport java.net.HttpCookie;\n\nimport com.netflix.hystrix.HystrixCommand;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\n\n/**\n * Sample HystrixCommand simulating one that would fetch UserAccount objects from a remote service or database.\n * <p>\n * This uses request caching and fallback behavior.\n */\npublic class GetUserAccountCommand extends HystrixCommand<UserAccount> {\n\n    private final HttpCookie httpCookie;\n    private final UserCookie userCookie;\n\n    /**\n     * \n     * @param cookie\n     * @throws IllegalArgumentException\n     *             if cookie is invalid meaning the user is not authenticated\n     */\n    public GetUserAccountCommand(HttpCookie cookie) {\n        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(\"User\")));\n        this.httpCookie = cookie;\n        /* parse or throw an IllegalArgumentException */\n        this.userCookie = UserCookie.parseCookie(httpCookie);\n    }\n\n    @Override\n    protected UserAccount run() {\n        /* simulate performing network call to retrieve user information */\n        try {\n            Thread.sleep((int) (Math.random() * 10) + 2);\n        } catch (InterruptedException e) {\n            // do nothing\n        }\n\n        /* fail 5% of the time to show how fallback works */\n        if (Math.random() > 0.95) {\n            throw new RuntimeException(\"random failure processing UserAccount network response\");\n        }\n\n        /* latency spike 5% of the time so timeouts can be triggered occasionally */\n        if (Math.random() > 0.95) {\n            // random latency spike\n            try {\n                Thread.sleep((int) (Math.random() * 300) + 25);\n            } catch (InterruptedException e) {\n                // do nothing\n            }\n        }\n\n        /* success ... create UserAccount with data \"from\" the remote service response */\n        return new UserAccount(86975, \"John James\", 2, true, false, true);\n    }\n\n    /**\n     * Use the HttpCookie value as the cacheKey so multiple executions\n     * in the same HystrixRequestContext will respond from cache.\n     */\n    @Override\n    protected String getCacheKey() {\n        return httpCookie.getValue();\n    }\n\n    /**\n     * Fallback that will use data from the UserCookie and stubbed defaults\n     * to create a UserAccount if the network call failed.\n     */\n    @Override\n    protected UserAccount getFallback() {\n        /*\n         * first 3 come from the HttpCookie\n         * next 3 are stubbed defaults\n         */\n        return new UserAccount(userCookie.userId, userCookie.name, userCookie.accountType, true, true, true);\n    }\n\n    /**\n     * Represents values containing in the cookie.\n     * <p>\n     * A real version of this could handle decrypting a secure HTTPS cookie.\n     */\n    private static class UserCookie {\n        /**\n         * Parse an HttpCookie into a UserCookie or IllegalArgumentException if invalid cookie\n         * \n         * @param cookie\n         * @return UserCookie\n         * @throws IllegalArgumentException\n         *             if cookie is invalid\n         */\n        private static UserCookie parseCookie(HttpCookie cookie) {\n            /* real code would parse the cookie here */\n            if (Math.random() < 0.998) {\n                /* valid cookie */\n                return new UserCookie(12345, \"Henry Peter\", 1);\n            } else {\n                /* invalid cookie */\n                throw new IllegalArgumentException();\n            }\n        }\n\n        public UserCookie(int userId, String name, int accountType) {\n            this.userId = userId;\n            this.name = name;\n            this.accountType = accountType;\n        }\n\n        private final int userId;\n        private final String name;\n        private final int accountType;\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/HystrixCommandAsyncDemo.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport java.math.BigDecimal;\nimport java.net.HttpCookie;\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Action0;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\nimport rx.plugins.RxJavaPlugins;\nimport rx.plugins.RxJavaSchedulersHook;\n\n/**\n * Executable client that demonstrates the lifecycle, metrics, request log and behavior of HystrixCommands.\n */\npublic class HystrixCommandAsyncDemo {\n\n//    public static void main(String args[]) {\n//        new HystrixCommandAsyncDemo().startDemo(true);\n//    }\n\n    static class ContextAwareRxSchedulersHook extends RxJavaSchedulersHook {\n        @Override\n        public Action0 onSchedule(final Action0 initialAction) {\n            final Runnable initialRunnable = new Runnable() {\n                @Override\n                public void run() {\n                    initialAction.call();\n                }\n            };\n            final Runnable wrappedRunnable =\n                    new HystrixContextRunnable(initialRunnable);\n            return new Action0() {\n                @Override\n                public void call() {\n                    wrappedRunnable.run();\n                }\n            };\n        }\n    }\n\n    public HystrixCommandAsyncDemo() {\n        /*\n         * Instead of using injected properties we'll set them via Archaius\n         * so the rest of the code behaves as it would in a real system\n         * where it picks up properties externally provided.\n         */\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.threadpool.default.coreSize\", 8);\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.CreditCardCommand.execution.isolation.thread.timeoutInMilliseconds\", 3000);\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.GetUserAccountCommand.execution.isolation.thread.timeoutInMilliseconds\", 50);\n        // set the rolling percentile more granular so we see data change every second rather than every 10 seconds as is the default \n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.default.metrics.rollingPercentile.numBuckets\", 60);\n\n        RxJavaPlugins.getInstance().registerSchedulersHook(new ContextAwareRxSchedulersHook());\n    }\n\n    public void startDemo(final boolean shouldLog) {\n        startMetricsMonitor(shouldLog);\n        while (true) {\n            final HystrixRequestContext context = HystrixRequestContext.initializeContext();\n            Observable<CreditCardAuthorizationResult> o = observeSimulatedUserRequestForOrderConfirmationAndCreditCardPayment();\n\n            final CountDownLatch latch = new CountDownLatch(1);\n            o.subscribe(new Subscriber<CreditCardAuthorizationResult>() {\n                @Override\n                public void onCompleted() {\n                    latch.countDown();\n                    context.shutdown();\n                }\n\n                @Override\n                public void onError(Throwable e) {\n                    e.printStackTrace();\n                    latch.countDown();\n                    context.shutdown();\n                }\n\n                @Override\n                public void onNext(CreditCardAuthorizationResult creditCardAuthorizationResult) {\n                    if (shouldLog) {\n                        System.out.println(\"Request => \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                    }\n                }\n            });\n\n            try {\n                latch.await(5000, TimeUnit.MILLISECONDS);\n            } catch (InterruptedException ex) {\n                System.out.println(\"INTERRUPTED!\");\n            }\n        }\n    }\n\n    private final static Random r = new Random();\n\n    private class Pair<A, B> {\n        private final A a;\n        private final B b;\n\n        Pair(A a, B b) {\n            this.a = a;\n            this.b = b;\n        }\n\n        A a() {\n            return this.a;\n        }\n\n        B b() {\n            return this.b;\n        }\n    }\n\n    public Observable<CreditCardAuthorizationResult> observeSimulatedUserRequestForOrderConfirmationAndCreditCardPayment() {\n        /* fetch user object with http cookies */\n        try {\n            Observable<UserAccount> user = new GetUserAccountCommand(new HttpCookie(\"mockKey\", \"mockValueFromHttpRequest\")).observe();\n            /* fetch the payment information (asynchronously) for the user so the credit card payment can proceed */\n            Observable<PaymentInformation> paymentInformation = user.flatMap(new Func1<UserAccount, Observable<PaymentInformation>>() {\n                @Override\n                public Observable<PaymentInformation> call(UserAccount userAccount) {\n                    return new GetPaymentInformationCommand(userAccount).observe();\n                }\n            });\n\n            /* fetch the order we're processing for the user */\n            int orderIdFromRequestArgument = 13579;\n            final Observable<Order> previouslySavedOrder = new GetOrderCommand(orderIdFromRequestArgument).observe();\n\n            return Observable.zip(paymentInformation, previouslySavedOrder, new Func2<PaymentInformation, Order, Pair<PaymentInformation, Order>>() {\n                @Override\n                public Pair<PaymentInformation, Order> call(PaymentInformation paymentInformation, Order order) {\n                    return new Pair<PaymentInformation, Order>(paymentInformation, order);\n                }\n            }).flatMap(new Func1<Pair<PaymentInformation, Order>, Observable<CreditCardAuthorizationResult>>() {\n                @Override\n                public Observable<CreditCardAuthorizationResult> call(Pair<PaymentInformation, Order> pair) {\n                    return new CreditCardCommand(pair.b(), pair.a(), new BigDecimal(123.45)).observe();\n                }\n            });\n        } catch (IllegalArgumentException ex) {\n            return Observable.error(ex);\n        }\n\n\n    }\n\n    public void startMetricsMonitor(final boolean shouldLog) {\n        Thread t = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                while (true) {\n                    /**\n                     * Since this is a simple example and we know the exact HystrixCommandKeys we are interested in\n                     * we will retrieve the HystrixCommandMetrics objects directly.\n                     *\n                     * Typically you would instead retrieve metrics from where they are published which is by default\n                     * done using Servo: https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring\n                     */\n\n                    // wait 5 seconds on each loop\n                    try {\n                        Thread.sleep(5000);\n                    } catch (Exception e) {\n                        // ignore\n                    }\n\n                    // we are using default names so can use class.getSimpleName() to derive the keys\n                    HystrixCommandMetrics creditCardMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(CreditCardCommand.class.getSimpleName()));\n                    HystrixCommandMetrics orderMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetOrderCommand.class.getSimpleName()));\n                    HystrixCommandMetrics userAccountMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetUserAccountCommand.class.getSimpleName()));\n                    HystrixCommandMetrics paymentInformationMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetPaymentInformationCommand.class.getSimpleName()));\n\n                    if (shouldLog) {\n                        // print out metrics\n                        StringBuilder out = new StringBuilder();\n                        out.append(\"\\n\");\n                        out.append(\"#####################################################################################\").append(\"\\n\");\n                        out.append(\"# CreditCardCommand: \" + getStatsStringFromMetrics(creditCardMetrics)).append(\"\\n\");\n                        out.append(\"# GetOrderCommand: \" + getStatsStringFromMetrics(orderMetrics)).append(\"\\n\");\n                        out.append(\"# GetUserAccountCommand: \" + getStatsStringFromMetrics(userAccountMetrics)).append(\"\\n\");\n                        out.append(\"# GetPaymentInformationCommand: \" + getStatsStringFromMetrics(paymentInformationMetrics)).append(\"\\n\");\n                        out.append(\"#####################################################################################\").append(\"\\n\");\n                        System.out.println(out.toString());\n                    }\n                }\n            }\n\n            private String getStatsStringFromMetrics(HystrixCommandMetrics metrics) {\n                StringBuilder m = new StringBuilder();\n                if (metrics != null) {\n                    HealthCounts health = metrics.getHealthCounts();\n                    m.append(\"Requests: \").append(health.getTotalRequests()).append(\" \");\n                    m.append(\"Errors: \").append(health.getErrorCount()).append(\" (\").append(health.getErrorPercentage()).append(\"%)   \");\n                    m.append(\"Mean: \").append(metrics.getExecutionTimePercentile(50)).append(\" \");\n                    m.append(\"75th: \").append(metrics.getExecutionTimePercentile(75)).append(\" \");\n                    m.append(\"90th: \").append(metrics.getExecutionTimePercentile(90)).append(\" \");\n                    m.append(\"99th: \").append(metrics.getExecutionTimePercentile(99)).append(\" \");\n                }\n                return m.toString();\n            }\n\n        });\n        t.setDaemon(true);\n        t.start();\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/HystrixCommandDemo.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport java.math.BigDecimal;\nimport java.net.HttpCookie;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport com.netflix.config.ConfigurationManager;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;\nimport com.netflix.hystrix.HystrixRequestLog;\nimport com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;\n\n/**\n * Executable client that demonstrates the lifecycle, metrics, request log and behavior of HystrixCommands.\n */\npublic class HystrixCommandDemo {\n\n    public static void main(String args[]) {\n        new HystrixCommandDemo().startDemo();\n    }\n\n    public HystrixCommandDemo() {\n        /*\n         * Instead of using injected properties we'll set them via Archaius\n         * so the rest of the code behaves as it would in a real system\n         * where it picks up properties externally provided.\n         */\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.threadpool.default.coreSize\", 8);\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.CreditCardCommand.execution.isolation.thread.timeoutInMilliseconds\", 3000);\n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.GetUserAccountCommand.execution.isolation.thread.timeoutInMilliseconds\", 50);\n        // set the rolling percentile more granular so we see data change every second rather than every 10 seconds as is the default \n        ConfigurationManager.getConfigInstance().setProperty(\"hystrix.command.default.metrics.rollingPercentile.numBuckets\", 60);\n    }\n\n    /*\n     * Thread-pool to simulate HTTP requests.\n     * \n     * Use CallerRunsPolicy so we can just keep iterating and adding to it and it will block when full.\n     */\n    private final ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 5, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());\n\n    public void startDemo() {\n        startMetricsMonitor();\n        while (true) {\n            runSimulatedRequestOnThread();\n        }\n    }\n\n    public void runSimulatedRequestOnThread() {\n        pool.execute(new Runnable() {\n\n            @Override\n            public void run() {\n                HystrixRequestContext context = HystrixRequestContext.initializeContext();\n                try {\n                    executeSimulatedUserRequestForOrderConfirmationAndCreditCardPayment();\n\n                    System.out.println(\"Request => \" + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                } finally {\n                    context.shutdown();\n                }\n            }\n\n        });\n    }\n\n    public void executeSimulatedUserRequestForOrderConfirmationAndCreditCardPayment() throws InterruptedException, ExecutionException {\n        /* fetch user object with http cookies */\n        UserAccount user = new GetUserAccountCommand(new HttpCookie(\"mockKey\", \"mockValueFromHttpRequest\")).execute();\n\n        /* fetch the payment information (asynchronously) for the user so the credit card payment can proceed */\n        Future<PaymentInformation> paymentInformation = new GetPaymentInformationCommand(user).queue();\n\n        /* fetch the order we're processing for the user */\n        int orderIdFromRequestArgument = 13579;\n        Order previouslySavedOrder = new GetOrderCommand(orderIdFromRequestArgument).execute();\n\n        CreditCardCommand credit = new CreditCardCommand(previouslySavedOrder, paymentInformation.get(), new BigDecimal(123.45));\n        credit.execute();\n    }\n\n    public void startMetricsMonitor() {\n        Thread t = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                while (true) {\n                    /**\n                     * Since this is a simple example and we know the exact HystrixCommandKeys we are interested in\n                     * we will retrieve the HystrixCommandMetrics objects directly.\n                     * \n                     * Typically you would instead retrieve metrics from where they are published which is by default\n                     * done using Servo: https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring\n                     */\n\n                    // wait 5 seconds on each loop\n                    try {\n                        Thread.sleep(5000);\n                    } catch (Exception e) {\n                        // ignore\n                    }\n\n                    // we are using default names so can use class.getSimpleName() to derive the keys\n                    HystrixCommandMetrics creditCardMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(CreditCardCommand.class.getSimpleName()));\n                    HystrixCommandMetrics orderMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetOrderCommand.class.getSimpleName()));\n                    HystrixCommandMetrics userAccountMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetUserAccountCommand.class.getSimpleName()));\n                    HystrixCommandMetrics paymentInformationMetrics = HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(GetPaymentInformationCommand.class.getSimpleName()));\n\n                    // print out metrics\n                    StringBuilder out = new StringBuilder();\n                    out.append(\"\\n\");\n                    out.append(\"#####################################################################################\").append(\"\\n\");\n                    out.append(\"# CreditCardCommand: \" + getStatsStringFromMetrics(creditCardMetrics)).append(\"\\n\");\n                    out.append(\"# GetOrderCommand: \" + getStatsStringFromMetrics(orderMetrics)).append(\"\\n\");\n                    out.append(\"# GetUserAccountCommand: \" + getStatsStringFromMetrics(userAccountMetrics)).append(\"\\n\");\n                    out.append(\"# GetPaymentInformationCommand: \" + getStatsStringFromMetrics(paymentInformationMetrics)).append(\"\\n\");\n                    out.append(\"#####################################################################################\").append(\"\\n\");\n                    System.out.println(out.toString());\n                }\n            }\n\n            private String getStatsStringFromMetrics(HystrixCommandMetrics metrics) {\n                StringBuilder m = new StringBuilder();\n                if (metrics != null) {\n                    HealthCounts health = metrics.getHealthCounts();\n                    m.append(\"Requests: \").append(health.getTotalRequests()).append(\" \");\n                    m.append(\"Errors: \").append(health.getErrorCount()).append(\" (\").append(health.getErrorPercentage()).append(\"%)   \");\n                    m.append(\"Mean: \").append(metrics.getExecutionTimePercentile(50)).append(\" \");\n                    m.append(\"75th: \").append(metrics.getExecutionTimePercentile(75)).append(\" \");\n                    m.append(\"90th: \").append(metrics.getExecutionTimePercentile(90)).append(\" \");\n                    m.append(\"99th: \").append(metrics.getExecutionTimePercentile(99)).append(\" \");\n                }\n                return m.toString();\n            }\n\n        });\n        t.setDaemon(true);\n        t.start();\n    }\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/Order.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\nimport java.net.HttpCookie;\n\n/**\n * POJO \n */\npublic class Order {\n\n    private final int orderId;\n    private UserAccount user;\n\n    public Order(int orderId) {\n        this.orderId = orderId;\n\n        /* a contrived example of calling GetUserAccount again */\n        user = new GetUserAccountCommand(new HttpCookie(\"mockKey\", \"mockValueFromHttpRequest\")).execute();\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/PaymentInformation.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\n/**\n * POJO\n */\npublic class PaymentInformation {\n\n    private final UserAccount user;\n    private final String creditCardNumber;\n    private final int expirationMonth;\n    private final int expirationYear;\n\n    public PaymentInformation(UserAccount user, String creditCardNumber, int expirationMonth, int expirationYear) {\n        this.user = user;\n        this.creditCardNumber = creditCardNumber;\n        this.expirationMonth = expirationMonth;\n        this.expirationYear = expirationYear;\n    }\n\n    public String getCreditCardNumber() {\n        return creditCardNumber;\n    }\n\n    public int getExpirationMonth() {\n        return expirationMonth;\n    }\n\n    public int getExpirationYear() {\n        return expirationYear;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples/src/main/java/com/netflix/hystrix/examples/demo/UserAccount.java",
    "content": "/**\n * Copyright 2012 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.examples.demo;\n\n/**\n * Simple POJO to represent a user and their metadata.\n */\npublic class UserAccount {\n\n    private final int userId;\n    private final String name;\n    private final int accountType;\n    private final boolean isFeatureXenabled;\n    private final boolean isFeatureYenabled;\n    private final boolean isFeatureZenabled;\n\n    public UserAccount(int userId, String name, int accountType, boolean x, boolean y, boolean z) {\n        this.userId = userId;\n        this.name = name;\n        this.accountType = accountType;\n        this.isFeatureXenabled = x;\n        this.isFeatureYenabled = y;\n        this.isFeatureZenabled = z;\n    }\n\n    public int getUserId() {\n        return userId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public int getAccountType() {\n        return accountType;\n    }\n\n    public boolean isFeatureXenabled() {\n        return isFeatureXenabled;\n    }\n\n    public boolean isFeatureYenabled() {\n        return isFeatureYenabled;\n    }\n\n    public boolean isFeatureZenabled() {\n        return isFeatureZenabled;\n    }\n\n}\n"
  },
  {
    "path": "hystrix-examples-webapp/README.md",
    "content": "# hystrix-examples-webapp\n\nWeb application that demonstrates functionality from [hystrix-examples](https://github.com/Netflix/Hystrix/tree/master/hystrix-examples) and functionality from [hystrix-request-servlet](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-request-servlet) and [hystrix-metrics-event-stream](https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-metrics-event-stream).\n\nThe [hystrix-dashboard](https://github.com/Netflix/Hystrix/tree/master/hystrix-dashboard) can be used on this example app to monitor its metrics.\n\n# Run via Gradle\n\n```\n$ git clone git@github.com:Netflix/Hystrix.git\n$ cd Hystrix/hystrix-examples-webapp\n$ ../gradlew appRun\n> Building > :hystrix-examples-webapp:appRun > Running at http://localhost:8989/hystrix-examples-webapp\n```\n\nOnce running, open <a href=\"http://localhost:8989/hystrix-examples-webapp\">http://localhost:8989/hystrix-examples-webapp</a>.\n\n\n<img src=\"https://raw.github.com/wiki/Netflix/Hystrix/images/hystrix-examples-webapp-home.png\">\n"
  },
  {
    "path": "hystrix-examples-webapp/build.gradle",
    "content": "buildscript {\n    repositories {\n        maven {\n            url \"https://plugins.gradle.org/m2/\"\n        }\n    }\n    dependencies {\n        classpath \"org.gretty:gretty:3.0.5\"\n    }\n}\n\napply plugin: \"org.gretty\"\napply plugin: 'war'\n\n\ndependencies {\n    api project(':hystrix-core')\n    api project(':hystrix-examples')\n    api project(':hystrix-request-servlet')\n    api project(':hystrix-metrics-event-stream')\n}\n\ngretty {\n\thttpPort = 8989\n\tservletContainer = 'jetty9'\n}\n"
  },
  {
    "path": "hystrix-examples-webapp/src/main/webapp/WEB-INF/classes/log4j.properties",
    "content": "log4j.rootLogger=INFO, FILE\nlog4j.appender.FILE=org.apache.log4j.ConsoleAppender\nlog4j.appender.FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p  %C:%L [%C{1}] [%M]: %m%n\n\nlog4j.appender.FILE.httpclient=ERROR\n"
  },
  {
    "path": "hystrix-examples-webapp/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:web=\"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"\n\tversion=\"2.5\">\n\n\t<filter>\n\t\t<display-name>HystrixRequestContextServletFilter</display-name>\n\t\t<filter-name>HystrixRequestContextServletFilter</filter-name>\n\t\t<filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>HystrixRequestContextServletFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\t\n\t<filter>\n\t\t<display-name>HystrixRequestLogViaResponseHeaderServletFilter</display-name>\n\t\t<filter-name>HystrixRequestLogViaResponseHeaderServletFilter</filter-name>\n\t\t<filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaResponseHeaderServletFilter</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>HystrixRequestLogViaResponseHeaderServletFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\n\t<servlet>\n\t\t<description></description>\n\t\t<display-name>HystrixMetricsStreamServlet</display-name>\n\t\t<servlet-name>HystrixMetricsStreamServlet</servlet-name>\n\t\t<servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>\n\t</servlet>\n\n\t<servlet-mapping>\n\t\t<servlet-name>HystrixMetricsStreamServlet</servlet-name>\n\t\t<url-pattern>/hystrix.stream</url-pattern>\n\t</servlet-mapping>\n\n\t<servlet>\n\t\t<description></description>\n\t\t<display-name>HystrixConfigSseServlet</display-name>\n\t\t<servlet-name>HystrixConfigSseServlet</servlet-name>\n\t\t<servlet-class>com.netflix.hystrix.contrib.sample.stream.HystrixConfigSseServlet</servlet-class>\n\t</servlet>\n\n\t<servlet-mapping>\n\t\t<servlet-name>HystrixConfigSseServlet</servlet-name>\n\t\t<url-pattern>/hystrix/config.stream</url-pattern>\n\t</servlet-mapping>\n\n    <servlet>\n        <description></description>\n        <display-name>HystrixUtilizationSseServlet</display-name>\n        <servlet-name>HystrixUtilizationSseServlet</servlet-name>\n        <servlet-class>com.netflix.hystrix.contrib.sample.stream.HystrixUtilizationSseServlet</servlet-class>\n    </servlet>\n\n    <servlet-mapping>\n        <servlet-name>HystrixUtilizationSseServlet</servlet-name>\n        <url-pattern>/hystrix/utilization.stream</url-pattern>\n    </servlet-mapping>\n\n    <servlet>\n        <description></description>\n        <display-name>HystrixRequestEventsSseServlet</display-name>\n        <servlet-name>HystrixRequestEventsSseServlet</servlet-name>\n        <servlet-class>com.netflix.hystrix.contrib.requests.stream.HystrixRequestEventsSseServlet</servlet-class>\n    </servlet>\n\n    <servlet-mapping>\n        <servlet-name>HystrixRequestEventsSseServlet</servlet-name>\n        <url-pattern>/hystrix/requests.stream</url-pattern>\n    </servlet-mapping>\n\n</web-app>\n"
  },
  {
    "path": "hystrix-examples-webapp/src/main/webapp/index.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=ISO-8859-1\"\n    pageEncoding=\"ISO-8859-1\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>HystrixCommandDemo Execution and HystrixRequestLog [hystrix-examples-webapp]</title>\n</head>\n<body>\n<div style=\"width:800px;margin:0 auto;\">\n\t\n\t<center><h2>HystrixCommandDemo Execution and HystrixRequestLog<br>[hystrix-examples-webapp]</h2></center>\n\t<center><img width=\"264\" height=\"233\" src=\"https://raw.github.com/wiki/Netflix/Hystrix/images/hystrix-logo.png\"></center>\n\t<p>\n\t\tThe following is the output of <i>HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()</i> after simulating the execution of several commands.\n\t</p>\n\t<p>\n\t\tThe simulation code is in com.netflix.hystrix.examples.demo.HystrixCommandDemo.\n\t</p>\n\t<%@ page import=\"com.netflix.hystrix.examples.demo.HystrixCommandDemo, com.netflix.hystrix.HystrixRequestLog\" %>\n\t<%\n\tnew HystrixCommandDemo().executeSimulatedUserRequestForOrderConfirmationAndCreditCardPayment();\n\t%>\n\t<hr>\n\t<b><%=\tHystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString() %></b>\n\t<hr>\n\t<p>\n\t\tThis request log is also part of the HTTP response header with key name \"X-HystrixLog\".\n\t</p>\n\t<p>\n\t\tYou can view the realtime stream at <a href=\"./hystrix.stream\">./hystrix.stream</a>.\n\t</p>\n\t<p>\n\t\tTo see the realtime stream change over time execute the following (with correct hostname, port etc) to keep accessing the webapp while watching the stream and you will see the metrics change:\n\t</p>\n\t<pre>\n\twhile true ; do curl \"http://localhost:8989/hystrix-examples-webapp\"; done\n\t</pre>\n\t<p>\n\tThe configuration of Hystrix for this functionality is done in web.xml as follows:\n\t</p>\n<pre>\n\t&lt;filter&gt;\n\t\t&lt;display-name&gt;HystrixRequestContextServletFilter&lt;/display-name&gt;\n\t\t&lt;filter-name&gt;HystrixRequestContextServletFilter&lt;/filter-name&gt;\n\t\t&lt;filter-class&gt;com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter&lt;/filter-class&gt;\n\t&lt;/filter&gt;\n\t&lt;filter-mapping&gt;\n\t\t&lt;filter-name&gt;HystrixRequestContextServletFilter&lt;/filter-name&gt;\n\t\t&lt;url-pattern&gt;/*&lt;/url-pattern&gt;\n\t&lt;/filter-mapping&gt;\n\t\n\t&lt;filter&gt;\n\t\t&lt;display-name&gt;HystrixRequestLogViaResponseHeaderServletFilter&lt;/display-name&gt;\n\t\t&lt;filter-name&gt;HystrixRequestLogViaResponseHeaderServletFilter&lt;/filter-name&gt;\n\t\t&lt;filter-class&gt;com.netflix.hystrix.contrib.requestservlet.HystrixRequestLogViaResponseHeaderServletFilter&lt;/filter-class&gt;\n\t&lt;/filter&gt;\n\t&lt;filter-mapping&gt;\n\t\t&lt;filter-name&gt;HystrixRequestLogViaResponseHeaderServletFilter&lt;/filter-name&gt;\n\t\t&lt;url-pattern&gt;/*&lt;/url-pattern&gt;\n\t&lt;/filter-mapping&gt;\n\n\t&lt;servlet&gt;\n\t\t&lt;description&gt;&lt;/description&gt;\n\t\t&lt;display-name&gt;HystrixMetricsStreamServlet&lt;/display-name&gt;\n\t\t&lt;servlet-name&gt;HystrixMetricsStreamServlet&lt;/servlet-name&gt;\n\t\t&lt;servlet-class&gt;com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet&lt;/servlet-class&gt;\n\t&lt;/servlet&gt;\n\n\t&lt;servlet-mapping&gt;\n\t\t&lt;servlet-name&gt;HystrixMetricsStreamServlet&lt;/servlet-name&gt;\n\t\t&lt;url-pattern&gt;/hystrix.stream&lt;/url-pattern&gt;\n\t&lt;/servlet-mapping&gt;\n</pre>\n\n</div>\n</body>\n</html>"
  },
  {
    "path": "hystrix-serialization/build.gradle",
    "content": "repositories {\n    mavenCentral()\n}\n\n\ndependencies {\n    api project(':hystrix-core')\n\n\t//if we bump into the the 2.8.0 series, we are forced to use Java7\n    api 'com.fasterxml.jackson.core:jackson-core:2.7.5'\n    api 'com.fasterxml.jackson.core:jackson-databind:2.7.5'\n    api 'com.fasterxml.jackson.core:jackson-annotations:2.7.5'\n    implementation 'com.fasterxml.jackson.module:jackson-module-afterburner:2.7.5'\n\t\n    testImplementation 'junit:junit-dep:4.10'\n    testImplementation 'org.mockito:mockito-all:1.9.5'\n\ttestImplementation project(':hystrix-core').sourceSets.test.output\n\ttestImplementation project(':hystrix-junit')\n}\n"
  },
  {
    "path": "hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixConfiguration.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.config.HystrixCollapserConfiguration;\nimport com.netflix.hystrix.config.HystrixCommandConfiguration;\nimport com.netflix.hystrix.config.HystrixConfiguration;\nimport com.netflix.hystrix.config.HystrixThreadPoolConfiguration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.nio.ByteBuffer;\nimport java.util.Map;\n\npublic class SerialHystrixConfiguration extends SerialHystrixMetric {\n\n    private static final Logger logger = LoggerFactory.getLogger(SerialHystrixConfiguration.class);\n\n    @Deprecated\n    public static byte[] toBytes(HystrixConfiguration config) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    public static String toJsonString(HystrixConfiguration config) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n            serializeConfiguration(config, json);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        return jsonString.getBuffer().toString();\n    }\n\n    private static void serializeConfiguration(HystrixConfiguration config, JsonGenerator json) {\n        try {\n            json.writeStartObject();\n            json.writeStringField(\"type\", \"HystrixConfig\");\n            json.writeObjectFieldStart(\"commands\");\n            for (Map.Entry<HystrixCommandKey, HystrixCommandConfiguration> entry: config.getCommandConfig().entrySet()) {\n                final HystrixCommandKey key = entry.getKey();\n                final HystrixCommandConfiguration commandConfig = entry.getValue();\n                writeCommandConfigJson(json, key, commandConfig);\n\n            }\n            json.writeEndObject();\n\n            json.writeObjectFieldStart(\"threadpools\");\n            for (Map.Entry<HystrixThreadPoolKey, HystrixThreadPoolConfiguration> entry: config.getThreadPoolConfig().entrySet()) {\n                final HystrixThreadPoolKey threadPoolKey = entry.getKey();\n                final HystrixThreadPoolConfiguration threadPoolConfig = entry.getValue();\n                writeThreadPoolConfigJson(json, threadPoolKey, threadPoolConfig);\n            }\n            json.writeEndObject();\n\n            json.writeObjectFieldStart(\"collapsers\");\n            for (Map.Entry<HystrixCollapserKey, HystrixCollapserConfiguration> entry: config.getCollapserConfig().entrySet()) {\n                final HystrixCollapserKey collapserKey = entry.getKey();\n                final HystrixCollapserConfiguration collapserConfig = entry.getValue();\n                writeCollapserConfigJson(json, collapserKey, collapserConfig);\n            }\n            json.writeEndObject();\n            json.writeEndObject();\n            json.close();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n    }\n\n    @Deprecated\n    public static HystrixConfiguration fromByteBuffer(ByteBuffer bb) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    private static void writeCommandConfigJson(JsonGenerator json, HystrixCommandKey key, HystrixCommandConfiguration commandConfig) throws IOException {\n        json.writeObjectFieldStart(key.name());\n        json.writeStringField(\"threadPoolKey\", commandConfig.getThreadPoolKey().name());\n        json.writeStringField(\"groupKey\", commandConfig.getGroupKey().name());\n        json.writeObjectFieldStart(\"execution\");\n        HystrixCommandConfiguration.HystrixCommandExecutionConfig executionConfig = commandConfig.getExecutionConfig();\n        json.writeStringField(\"isolationStrategy\", executionConfig.getIsolationStrategy().name());\n        json.writeStringField(\"threadPoolKeyOverride\", executionConfig.getThreadPoolKeyOverride());\n        json.writeBooleanField(\"requestCacheEnabled\", executionConfig.isRequestCacheEnabled());\n        json.writeBooleanField(\"requestLogEnabled\", executionConfig.isRequestLogEnabled());\n        json.writeBooleanField(\"timeoutEnabled\", executionConfig.isTimeoutEnabled());\n        json.writeBooleanField(\"fallbackEnabled\", executionConfig.isFallbackEnabled());\n        json.writeNumberField(\"timeoutInMilliseconds\", executionConfig.getTimeoutInMilliseconds());\n        json.writeNumberField(\"semaphoreSize\", executionConfig.getSemaphoreMaxConcurrentRequests());\n        json.writeNumberField(\"fallbackSemaphoreSize\", executionConfig.getFallbackMaxConcurrentRequest());\n        json.writeBooleanField(\"threadInterruptOnTimeout\", executionConfig.isThreadInterruptOnTimeout());\n        json.writeEndObject();\n        json.writeObjectFieldStart(\"metrics\");\n        HystrixCommandConfiguration.HystrixCommandMetricsConfig metricsConfig = commandConfig.getMetricsConfig();\n        json.writeNumberField(\"healthBucketSizeInMs\", metricsConfig.getHealthIntervalInMilliseconds());\n        json.writeNumberField(\"percentileBucketSizeInMilliseconds\", metricsConfig.getRollingPercentileBucketSizeInMilliseconds());\n        json.writeNumberField(\"percentileBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeBooleanField(\"percentileEnabled\", metricsConfig.isRollingPercentileEnabled());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", metricsConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n        json.writeObjectFieldStart(\"circuitBreaker\");\n        HystrixCommandConfiguration.HystrixCommandCircuitBreakerConfig circuitBreakerConfig = commandConfig.getCircuitBreakerConfig();\n        json.writeBooleanField(\"enabled\", circuitBreakerConfig.isEnabled());\n        json.writeBooleanField(\"isForcedOpen\", circuitBreakerConfig.isForceOpen());\n        json.writeBooleanField(\"isForcedClosed\", circuitBreakerConfig.isForceOpen());\n        json.writeNumberField(\"requestVolumeThreshold\", circuitBreakerConfig.getRequestVolumeThreshold());\n        json.writeNumberField(\"errorPercentageThreshold\", circuitBreakerConfig.getErrorThresholdPercentage());\n        json.writeNumberField(\"sleepInMilliseconds\", circuitBreakerConfig.getSleepWindowInMilliseconds());\n        json.writeEndObject();\n        json.writeEndObject();\n    }\n\n    private static void writeThreadPoolConfigJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolConfiguration threadPoolConfig) throws IOException {\n        json.writeObjectFieldStart(threadPoolKey.name());\n        json.writeNumberField(\"coreSize\", threadPoolConfig.getCoreSize());\n        json.writeNumberField(\"maximumSize\", threadPoolConfig.getMaximumSize());\n        json.writeNumberField(\"actualMaximumSize\", threadPoolConfig.getActualMaximumSize());\n        json.writeNumberField(\"maxQueueSize\", threadPoolConfig.getMaxQueueSize());\n        json.writeNumberField(\"queueRejectionThreshold\", threadPoolConfig.getQueueRejectionThreshold());\n        json.writeNumberField(\"keepAliveTimeInMinutes\", threadPoolConfig.getKeepAliveTimeInMinutes());\n        json.writeBooleanField(\"allowMaximumSizeToDivergeFromCoreSize\", threadPoolConfig.getAllowMaximumSizeToDivergeFromCoreSize());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", threadPoolConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", threadPoolConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n    }\n\n    private static void writeCollapserConfigJson(JsonGenerator json, HystrixCollapserKey collapserKey, HystrixCollapserConfiguration collapserConfig) throws IOException {\n        json.writeObjectFieldStart(collapserKey.name());\n        json.writeNumberField(\"maxRequestsInBatch\", collapserConfig.getMaxRequestsInBatch());\n        json.writeNumberField(\"timerDelayInMilliseconds\", collapserConfig.getTimerDelayInMilliseconds());\n        json.writeBooleanField(\"requestCacheEnabled\", collapserConfig.isRequestCacheEnabled());\n        json.writeObjectFieldStart(\"metrics\");\n        HystrixCollapserConfiguration.CollapserMetricsConfig metricsConfig = collapserConfig.getCollapserMetricsConfig();\n        json.writeNumberField(\"percentileBucketSizeInMilliseconds\", metricsConfig.getRollingPercentileBucketSizeInMilliseconds());\n        json.writeNumberField(\"percentileBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeBooleanField(\"percentileEnabled\", metricsConfig.isRollingPercentileEnabled());\n        json.writeNumberField(\"counterBucketSizeInMilliseconds\", metricsConfig.getRollingCounterBucketSizeInMilliseconds());\n        json.writeNumberField(\"counterBucketCount\", metricsConfig.getRollingCounterNumberOfBuckets());\n        json.writeEndObject();\n        json.writeEndObject();\n    }\n}\n"
  },
  {
    "path": "hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixDashboardData.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCircuitBreaker;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCollapserMetrics;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.HystrixThreadPoolMetrics;\nimport com.netflix.hystrix.metric.consumer.HystrixDashboardStream;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport rx.functions.Func0;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SerialHystrixDashboardData extends SerialHystrixMetric {\n\n    private static final Logger logger = LoggerFactory.getLogger(SerialHystrixDashboardData.class);\n\n    @Deprecated\n    public static byte[] toBytes(HystrixDashboardStream.DashboardData dashboardData) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    public static String toJsonString(HystrixDashboardStream.DashboardData dashboardData) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n            writeDashboardData(json, dashboardData);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        return jsonString.getBuffer().toString();\n    }\n\n    public static List<String> toMultipleJsonStrings(HystrixDashboardStream.DashboardData dashboardData) {\n        List<String> jsonStrings = new ArrayList<String>();\n\n        for (HystrixCommandMetrics commandMetrics : dashboardData.getCommandMetrics()) {\n            jsonStrings.add(toJsonString(commandMetrics));\n        }\n\n        for (HystrixThreadPoolMetrics threadPoolMetrics : dashboardData.getThreadPoolMetrics()) {\n            jsonStrings.add(toJsonString(threadPoolMetrics));\n        }\n\n        for (HystrixCollapserMetrics collapserMetrics : dashboardData.getCollapserMetrics()) {\n            jsonStrings.add(toJsonString(collapserMetrics));\n        }\n\n        return jsonStrings;\n    }\n\n    private static void writeDashboardData(JsonGenerator json, HystrixDashboardStream.DashboardData dashboardData) {\n        try {\n            json.writeStartArray();\n\n            for (HystrixCommandMetrics commandMetrics : dashboardData.getCommandMetrics()) {\n                writeCommandMetrics(commandMetrics, json);\n            }\n\n            for (HystrixThreadPoolMetrics threadPoolMetrics : dashboardData.getThreadPoolMetrics()) {\n                writeThreadPoolMetrics(threadPoolMetrics, json);\n            }\n\n            for (HystrixCollapserMetrics collapserMetrics : dashboardData.getCollapserMetrics()) {\n                writeCollapserMetrics(collapserMetrics, json);\n            }\n\n            json.writeEndArray();\n\n            json.close();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static String toJsonString(HystrixCommandMetrics commandMetrics) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n            writeCommandMetrics(commandMetrics, json);\n            json.close();\n            return jsonString.getBuffer().toString();\n        } catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n    }\n\n    public static String toJsonString(HystrixThreadPoolMetrics threadPoolMetrics) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n            writeThreadPoolMetrics(threadPoolMetrics, json);\n            json.close();\n            return jsonString.getBuffer().toString();\n        } catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n    }\n\n    public static String toJsonString(HystrixCollapserMetrics collapserMetrics) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n            writeCollapserMetrics(collapserMetrics, json);\n            json.close();\n            return jsonString.getBuffer().toString();\n        } catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n    }\n\n    private static void writeCommandMetrics(final HystrixCommandMetrics commandMetrics, JsonGenerator json) throws IOException {\n        HystrixCommandKey key = commandMetrics.getCommandKey();\n        HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);\n\n        json.writeStartObject();\n        json.writeStringField(\"type\", \"HystrixCommand\");\n        json.writeStringField(\"name\", key.name());\n        json.writeStringField(\"group\", commandMetrics.getCommandGroup().name());\n        json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n        // circuit breaker\n        if (circuitBreaker == null) {\n            // circuit breaker is disabled and thus never open\n            json.writeBooleanField(\"isCircuitBreakerOpen\", false);\n        } else {\n            json.writeBooleanField(\"isCircuitBreakerOpen\", circuitBreaker.isOpen());\n        }\n        HystrixCommandMetrics.HealthCounts healthCounts = commandMetrics.getHealthCounts();\n        json.writeNumberField(\"errorPercentage\", healthCounts.getErrorPercentage());\n        json.writeNumberField(\"errorCount\", healthCounts.getErrorCount());\n        json.writeNumberField(\"requestCount\", healthCounts.getTotalRequests());\n\n        // rolling counters\n        safelyWriteNumberField(json, \"rollingCountBadRequests\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.BAD_REQUEST);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountCollapsedRequests\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.COLLAPSED);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountEmit\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.EMIT);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountExceptionsThrown\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.EXCEPTION_THROWN);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFailure\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FAILURE);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFallbackEmit\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_EMIT);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFallbackFailure\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_FAILURE);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFallbackMissing\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_MISSING);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFallbackRejection\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_REJECTION);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountFallbackSuccess\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.FALLBACK_SUCCESS);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountResponsesFromCache\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.RESPONSE_FROM_CACHE);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountSemaphoreRejected\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.SEMAPHORE_REJECTED);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountShortCircuited\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.SHORT_CIRCUITED);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountSuccess\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.SUCCESS);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountThreadPoolRejected\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.THREAD_POOL_REJECTED);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountTimeout\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return commandMetrics.getRollingCount(HystrixEventType.TIMEOUT);\n            }\n        });\n\n        json.writeNumberField(\"currentConcurrentExecutionCount\", commandMetrics.getCurrentConcurrentExecutionCount());\n        json.writeNumberField(\"rollingMaxConcurrentExecutionCount\", commandMetrics.getRollingMaxConcurrentExecutions());\n\n        // latency percentiles\n        json.writeNumberField(\"latencyExecute_mean\", commandMetrics.getExecutionTimeMean());\n        json.writeObjectFieldStart(\"latencyExecute\");\n        json.writeNumberField(\"0\", commandMetrics.getExecutionTimePercentile(0));\n        json.writeNumberField(\"25\", commandMetrics.getExecutionTimePercentile(25));\n        json.writeNumberField(\"50\", commandMetrics.getExecutionTimePercentile(50));\n        json.writeNumberField(\"75\", commandMetrics.getExecutionTimePercentile(75));\n        json.writeNumberField(\"90\", commandMetrics.getExecutionTimePercentile(90));\n        json.writeNumberField(\"95\", commandMetrics.getExecutionTimePercentile(95));\n        json.writeNumberField(\"99\", commandMetrics.getExecutionTimePercentile(99));\n        json.writeNumberField(\"99.5\", commandMetrics.getExecutionTimePercentile(99.5));\n        json.writeNumberField(\"100\", commandMetrics.getExecutionTimePercentile(100));\n        json.writeEndObject();\n        //\n        json.writeNumberField(\"latencyTotal_mean\", commandMetrics.getTotalTimeMean());\n        json.writeObjectFieldStart(\"latencyTotal\");\n        json.writeNumberField(\"0\", commandMetrics.getTotalTimePercentile(0));\n        json.writeNumberField(\"25\", commandMetrics.getTotalTimePercentile(25));\n        json.writeNumberField(\"50\", commandMetrics.getTotalTimePercentile(50));\n        json.writeNumberField(\"75\", commandMetrics.getTotalTimePercentile(75));\n        json.writeNumberField(\"90\", commandMetrics.getTotalTimePercentile(90));\n        json.writeNumberField(\"95\", commandMetrics.getTotalTimePercentile(95));\n        json.writeNumberField(\"99\", commandMetrics.getTotalTimePercentile(99));\n        json.writeNumberField(\"99.5\", commandMetrics.getTotalTimePercentile(99.5));\n        json.writeNumberField(\"100\", commandMetrics.getTotalTimePercentile(100));\n        json.writeEndObject();\n\n        // property values for reporting what is actually seen by the command rather than what was set somewhere\n        HystrixCommandProperties commandProperties = commandMetrics.getProperties();\n\n        json.writeNumberField(\"propertyValue_circuitBreakerRequestVolumeThreshold\", commandProperties.circuitBreakerRequestVolumeThreshold().get());\n        json.writeNumberField(\"propertyValue_circuitBreakerSleepWindowInMilliseconds\", commandProperties.circuitBreakerSleepWindowInMilliseconds().get());\n        json.writeNumberField(\"propertyValue_circuitBreakerErrorThresholdPercentage\", commandProperties.circuitBreakerErrorThresholdPercentage().get());\n        json.writeBooleanField(\"propertyValue_circuitBreakerForceOpen\", commandProperties.circuitBreakerForceOpen().get());\n        json.writeBooleanField(\"propertyValue_circuitBreakerForceClosed\", commandProperties.circuitBreakerForceClosed().get());\n        json.writeBooleanField(\"propertyValue_circuitBreakerEnabled\", commandProperties.circuitBreakerEnabled().get());\n\n        json.writeStringField(\"propertyValue_executionIsolationStrategy\", commandProperties.executionIsolationStrategy().get().name());\n        json.writeNumberField(\"propertyValue_executionIsolationThreadTimeoutInMilliseconds\", commandProperties.executionTimeoutInMilliseconds().get());\n        json.writeNumberField(\"propertyValue_executionTimeoutInMilliseconds\", commandProperties.executionTimeoutInMilliseconds().get());\n        json.writeBooleanField(\"propertyValue_executionIsolationThreadInterruptOnTimeout\", commandProperties.executionIsolationThreadInterruptOnTimeout().get());\n        json.writeStringField(\"propertyValue_executionIsolationThreadPoolKeyOverride\", commandProperties.executionIsolationThreadPoolKeyOverride().get());\n        json.writeNumberField(\"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests\", commandProperties.executionIsolationSemaphoreMaxConcurrentRequests().get());\n        json.writeNumberField(\"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests\", commandProperties.fallbackIsolationSemaphoreMaxConcurrentRequests().get());\n\n                    /*\n                     * The following are commented out as these rarely change and are verbose for streaming for something people don't change.\n                     * We could perhaps allow a property or request argument to include these.\n                     */\n\n        //                    json.put(\"propertyValue_metricsRollingPercentileEnabled\", commandProperties.metricsRollingPercentileEnabled().get());\n        //                    json.put(\"propertyValue_metricsRollingPercentileBucketSize\", commandProperties.metricsRollingPercentileBucketSize().get());\n        //                    json.put(\"propertyValue_metricsRollingPercentileWindow\", commandProperties.metricsRollingPercentileWindowInMilliseconds().get());\n        //                    json.put(\"propertyValue_metricsRollingPercentileWindowBuckets\", commandProperties.metricsRollingPercentileWindowBuckets().get());\n        //                    json.put(\"propertyValue_metricsRollingStatisticalWindowBuckets\", commandProperties.metricsRollingStatisticalWindowBuckets().get());\n        json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", commandProperties.metricsRollingStatisticalWindowInMilliseconds().get());\n\n        json.writeBooleanField(\"propertyValue_requestCacheEnabled\", commandProperties.requestCacheEnabled().get());\n        json.writeBooleanField(\"propertyValue_requestLogEnabled\", commandProperties.requestLogEnabled().get());\n\n        json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n        json.writeStringField(\"threadPool\", commandMetrics.getThreadPoolKey().name());\n\n        json.writeEndObject();\n    }\n\n    private static void writeThreadPoolMetrics(final HystrixThreadPoolMetrics threadPoolMetrics, JsonGenerator json) throws IOException {\n        HystrixThreadPoolKey key = threadPoolMetrics.getThreadPoolKey();\n\n        json.writeStartObject();\n\n        json.writeStringField(\"type\", \"HystrixThreadPool\");\n        json.writeStringField(\"name\", key.name());\n        json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n        json.writeNumberField(\"currentActiveCount\", threadPoolMetrics.getCurrentActiveCount().intValue());\n        json.writeNumberField(\"currentCompletedTaskCount\", threadPoolMetrics.getCurrentCompletedTaskCount().longValue());\n        json.writeNumberField(\"currentCorePoolSize\", threadPoolMetrics.getCurrentCorePoolSize().intValue());\n        json.writeNumberField(\"currentLargestPoolSize\", threadPoolMetrics.getCurrentLargestPoolSize().intValue());\n        json.writeNumberField(\"currentMaximumPoolSize\", threadPoolMetrics.getCurrentMaximumPoolSize().intValue());\n        json.writeNumberField(\"currentPoolSize\", threadPoolMetrics.getCurrentPoolSize().intValue());\n        json.writeNumberField(\"currentQueueSize\", threadPoolMetrics.getCurrentQueueSize().intValue());\n        json.writeNumberField(\"currentTaskCount\", threadPoolMetrics.getCurrentTaskCount().longValue());\n        safelyWriteNumberField(json, \"rollingCountThreadsExecuted\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return threadPoolMetrics.getRollingCount(HystrixEventType.ThreadPool.EXECUTED);\n            }\n        });\n        json.writeNumberField(\"rollingMaxActiveThreads\", threadPoolMetrics.getRollingMaxActiveThreads());\n        safelyWriteNumberField(json, \"rollingCountCommandRejections\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return threadPoolMetrics.getRollingCount(HystrixEventType.ThreadPool.REJECTED);\n            }\n        });\n\n        json.writeNumberField(\"propertyValue_queueSizeRejectionThreshold\", threadPoolMetrics.getProperties().queueSizeRejectionThreshold().get());\n        json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", threadPoolMetrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get());\n\n        json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n\n        json.writeEndObject();\n    }\n\n    private static void writeCollapserMetrics(final HystrixCollapserMetrics collapserMetrics, JsonGenerator json) throws IOException  {\n        HystrixCollapserKey key = collapserMetrics.getCollapserKey();\n\n        json.writeStartObject();\n\n        json.writeStringField(\"type\", \"HystrixCollapser\");\n        json.writeStringField(\"name\", key.name());\n        json.writeNumberField(\"currentTime\", System.currentTimeMillis());\n\n        safelyWriteNumberField(json, \"rollingCountRequestsBatched\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return collapserMetrics.getRollingCount(HystrixEventType.Collapser.ADDED_TO_BATCH);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountBatches\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return collapserMetrics.getRollingCount(HystrixEventType.Collapser.BATCH_EXECUTED);\n            }\n        });\n        safelyWriteNumberField(json, \"rollingCountResponsesFromCache\", new Func0<Long>() {\n            @Override\n            public Long call() {\n                return collapserMetrics.getRollingCount(HystrixEventType.Collapser.RESPONSE_FROM_CACHE);\n            }\n        });\n\n        // batch size percentiles\n        json.writeNumberField(\"batchSize_mean\", collapserMetrics.getBatchSizeMean());\n        json.writeObjectFieldStart(\"batchSize\");\n        json.writeNumberField(\"25\", collapserMetrics.getBatchSizePercentile(25));\n        json.writeNumberField(\"50\", collapserMetrics.getBatchSizePercentile(50));\n        json.writeNumberField(\"75\", collapserMetrics.getBatchSizePercentile(75));\n        json.writeNumberField(\"90\", collapserMetrics.getBatchSizePercentile(90));\n        json.writeNumberField(\"95\", collapserMetrics.getBatchSizePercentile(95));\n        json.writeNumberField(\"99\", collapserMetrics.getBatchSizePercentile(99));\n        json.writeNumberField(\"99.5\", collapserMetrics.getBatchSizePercentile(99.5));\n        json.writeNumberField(\"100\", collapserMetrics.getBatchSizePercentile(100));\n        json.writeEndObject();\n\n        // shard size percentiles (commented-out for now)\n        //json.writeNumberField(\"shardSize_mean\", collapserMetrics.getShardSizeMean());\n        //json.writeObjectFieldStart(\"shardSize\");\n        //json.writeNumberField(\"25\", collapserMetrics.getShardSizePercentile(25));\n        //json.writeNumberField(\"50\", collapserMetrics.getShardSizePercentile(50));\n        //json.writeNumberField(\"75\", collapserMetrics.getShardSizePercentile(75));\n        //json.writeNumberField(\"90\", collapserMetrics.getShardSizePercentile(90));\n        //json.writeNumberField(\"95\", collapserMetrics.getShardSizePercentile(95));\n        //json.writeNumberField(\"99\", collapserMetrics.getShardSizePercentile(99));\n        //json.writeNumberField(\"99.5\", collapserMetrics.getShardSizePercentile(99.5));\n        //json.writeNumberField(\"100\", collapserMetrics.getShardSizePercentile(100));\n        //json.writeEndObject();\n\n        //json.writeNumberField(\"propertyValue_metricsRollingStatisticalWindowInMilliseconds\", collapserMetrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get());\n        json.writeBooleanField(\"propertyValue_requestCacheEnabled\", collapserMetrics.getProperties().requestCacheEnabled().get());\n        json.writeNumberField(\"propertyValue_maxRequestsInBatch\", collapserMetrics.getProperties().maxRequestsInBatch().get());\n        json.writeNumberField(\"propertyValue_timerDelayInMilliseconds\", collapserMetrics.getProperties().timerDelayInMilliseconds().get());\n\n        json.writeNumberField(\"reportingHosts\", 1); // this will get summed across all instances in a cluster\n\n        json.writeEndObject();\n    }\n\n    protected static void safelyWriteNumberField(JsonGenerator json, String name, Func0<Long> metricGenerator) throws IOException {\n        try {\n            json.writeNumberField(name, metricGenerator.call());\n        } catch (NoSuchFieldError error) {\n            logger.error(\"While publishing Hystrix metrics stream, error looking up eventType for : \" + name + \".  Please check that all Hystrix versions are the same!\");\n            json.writeNumberField(name, 0L);\n        }\n    }\n}\n"
  },
  {
    "path": "hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixMetric.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.fasterxml.jackson.core.JsonFactory;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.ByteBuffer;\n\npublic class SerialHystrixMetric {\n    protected final static JsonFactory jsonFactory = new JsonFactory();\n    protected final static ObjectMapper mapper = new ObjectMapper();\n    protected final static Logger logger = LoggerFactory.getLogger(SerialHystrixMetric.class);\n\n    @Deprecated\n    public static String fromByteBufferToString(ByteBuffer bb) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n}\n"
  },
  {
    "path": "hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixRequestEvents.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.metric.HystrixRequestEvents;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.List;\nimport java.util.Map;\n\npublic class SerialHystrixRequestEvents extends SerialHystrixMetric {\n\n    @Deprecated\n    public static byte[] toBytes(HystrixRequestEvents requestEvents) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    public static String toJsonString(HystrixRequestEvents requestEvents) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n            serializeRequestEvents(requestEvents, json);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        return jsonString.getBuffer().toString();\n    }\n\n    private static void serializeRequestEvents(HystrixRequestEvents requestEvents, JsonGenerator json) {\n        try {\n            json.writeStartArray();\n\n            for (Map.Entry<HystrixRequestEvents.ExecutionSignature, List<Integer>> entry: requestEvents.getExecutionsMappedToLatencies().entrySet()) {\n                convertExecutionToJson(json, entry.getKey(), entry.getValue());\n            }\n\n            json.writeEndArray();\n            json.close();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static void convertExecutionToJson(JsonGenerator json, HystrixRequestEvents.ExecutionSignature executionSignature, List<Integer> latencies) throws IOException {\n        json.writeStartObject();\n        json.writeStringField(\"name\", executionSignature.getCommandName());\n        json.writeArrayFieldStart(\"events\");\n        ExecutionResult.EventCounts eventCounts = executionSignature.getEventCounts();\n        for (HystrixEventType eventType: HystrixEventType.values()) {\n            if (!eventType.equals(HystrixEventType.COLLAPSED)) {\n                if (eventCounts.contains(eventType)) {\n                    int eventCount = eventCounts.getCount(eventType);\n                    if (eventCount > 1) {\n                        json.writeStartObject();\n                        json.writeStringField(\"name\", eventType.name());\n                        json.writeNumberField(\"count\", eventCount);\n                        json.writeEndObject();\n                    } else {\n                        json.writeString(eventType.name());\n                    }\n                }\n            }\n        }\n        json.writeEndArray();\n        json.writeArrayFieldStart(\"latencies\");\n        for (int latency: latencies) {\n            json.writeNumber(latency);\n        }\n        json.writeEndArray();\n        if (executionSignature.getCachedCount() > 0) {\n            json.writeNumberField(\"cached\", executionSignature.getCachedCount());\n        }\n        if (executionSignature.getEventCounts().contains(HystrixEventType.COLLAPSED)) {\n            json.writeObjectFieldStart(\"collapsed\");\n            json.writeStringField(\"name\", executionSignature.getCollapserKey().name());\n            json.writeNumberField(\"count\", executionSignature.getCollapserBatchSize());\n            json.writeEndObject();\n        }\n        json.writeEndObject();\n    }\n}\n"
  },
  {
    "path": "hystrix-serialization/src/main/java/com/netflix/hystrix/serial/SerialHystrixUtilization.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.metric.sample.HystrixCommandUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixThreadPoolUtilization;\nimport com.netflix.hystrix.metric.sample.HystrixUtilization;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.nio.ByteBuffer;\nimport java.util.Map;\n\npublic class SerialHystrixUtilization extends SerialHystrixMetric {\n\n    private final static Logger logger = LoggerFactory.getLogger(SerialHystrixUtilization.class);\n\n    @Deprecated\n    public static byte[] toBytes(HystrixUtilization utilization) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    public static String toJsonString(HystrixUtilization utilization) {\n        StringWriter jsonString = new StringWriter();\n\n        try {\n            JsonGenerator json = jsonFactory.createGenerator(jsonString);\n\n            serializeUtilization(utilization, json);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        return jsonString.getBuffer().toString();\n    }\n\n    private static void serializeUtilization(HystrixUtilization utilization, JsonGenerator json) {\n        try {\n            json.writeStartObject();\n            json.writeStringField(\"type\", \"HystrixUtilization\");\n            json.writeObjectFieldStart(\"commands\");\n            for (Map.Entry<HystrixCommandKey, HystrixCommandUtilization> entry: utilization.getCommandUtilizationMap().entrySet()) {\n                final HystrixCommandKey key = entry.getKey();\n                final HystrixCommandUtilization commandUtilization = entry.getValue();\n                writeCommandUtilizationJson(json, key, commandUtilization);\n\n            }\n            json.writeEndObject();\n\n            json.writeObjectFieldStart(\"threadpools\");\n            for (Map.Entry<HystrixThreadPoolKey, HystrixThreadPoolUtilization> entry: utilization.getThreadPoolUtilizationMap().entrySet()) {\n                final HystrixThreadPoolKey threadPoolKey = entry.getKey();\n                final HystrixThreadPoolUtilization threadPoolUtilization = entry.getValue();\n                writeThreadPoolUtilizationJson(json, threadPoolKey, threadPoolUtilization);\n            }\n            json.writeEndObject();\n            json.writeEndObject();\n            json.close();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Deprecated\n    public static HystrixUtilization fromByteBuffer(ByteBuffer bb) {\n        throw new UnsupportedOperationException(\"Not implemented anymore.  Will be implemented in a new class shortly\");\n    }\n\n    private static void writeCommandUtilizationJson(JsonGenerator json, HystrixCommandKey key, HystrixCommandUtilization utilization) throws IOException {\n        json.writeObjectFieldStart(key.name());\n        json.writeNumberField(\"activeCount\", utilization.getConcurrentCommandCount());\n        json.writeEndObject();\n    }\n\n    private static void writeThreadPoolUtilizationJson(JsonGenerator json, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolUtilization utilization) throws IOException {\n        json.writeObjectFieldStart(threadPoolKey.name());\n        json.writeNumberField(\"activeCount\", utilization.getCurrentActiveCount());\n        json.writeNumberField(\"queueSize\", utilization.getCurrentQueueSize());\n        json.writeNumberField(\"corePoolSize\", utilization.getCurrentCorePoolSize());\n        json.writeNumberField(\"poolSize\", utilization.getCurrentPoolSize());\n        json.writeEndObject();\n    }\n}\n"
  },
  {
    "path": "hystrix-serialization/src/test/java/com/netflix/hystrix/serial/SerialHystrixRequestEventsTest.java",
    "content": "/**\n * Copyright 2016 Netflix, Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.netflix.hystrix.serial;\n\nimport com.netflix.hystrix.ExecutionResult;\nimport com.netflix.hystrix.HystrixCollapserKey;\nimport com.netflix.hystrix.HystrixCommandGroupKey;\nimport com.netflix.hystrix.HystrixCommandKey;\nimport com.netflix.hystrix.HystrixCommandMetrics;\nimport com.netflix.hystrix.HystrixCommandProperties;\nimport com.netflix.hystrix.HystrixEventType;\nimport com.netflix.hystrix.HystrixInvokableInfo;\nimport com.netflix.hystrix.HystrixThreadPoolKey;\nimport com.netflix.hystrix.metric.HystrixRequestEvents;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\npublic class SerialHystrixRequestEventsTest {\n\n    private static final HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(\"GROUP\");\n    private static final HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(\"ThreadPool\");\n    private static final HystrixCommandKey fooKey = HystrixCommandKey.Factory.asKey(\"Foo\");\n    private static final HystrixCommandKey barKey = HystrixCommandKey.Factory.asKey(\"Bar\");\n    private static final HystrixCollapserKey collapserKey = HystrixCollapserKey.Factory.asKey(\"FooCollapser\");\n\n    @Test\n    public void testEmpty() throws IOException {\n        HystrixRequestEvents request = new HystrixRequestEvents(new ArrayList<HystrixInvokableInfo<?>>());\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[]\", actual);\n    }\n\n    @Test\n    public void testSingleSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[100]}]\", actual);\n    }\n\n    @Test\n    public void testSingleFailureFallbackMissing() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 101, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_MISSING\\\"],\\\"latencies\\\":[101]}]\", actual);\n    }\n\n    @Test\n    public void testSingleFailureFallbackSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 102, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[102]}]\", actual);\n    }\n\n    @Test\n    public void testSingleFailureFallbackRejected() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 103, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_REJECTION));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_REJECTION\\\"],\\\"latencies\\\":[103]}]\", actual);\n    }\n\n    @Test\n    public void testSingleFailureFallbackFailure() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 104, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_FAILURE));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_FAILURE\\\"],\\\"latencies\\\":[104]}]\", actual);\n    }\n\n    @Test\n    public void testSingleTimeoutFallbackSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 105, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"TIMEOUT\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[105]}]\", actual);\n    }\n\n    @Test\n    public void testSingleSemaphoreRejectedFallbackSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SEMAPHORE_REJECTED\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[1]}]\", actual);\n    }\n\n    @Test\n    public void testSingleThreadPoolRejectedFallbackSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"THREAD_POOL_REJECTED\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[1]}]\", actual);\n    }\n\n    @Test\n    public void testSingleShortCircuitedFallbackSuccess() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SHORT_CIRCUITED\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[1]}]\", actual);\n    }\n\n    @Test\n    public void testSingleBadRequest() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 50, HystrixEventType.BAD_REQUEST));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"BAD_REQUEST\\\"],\\\"latencies\\\":[50]}]\", actual);\n    }\n\n    @Test\n    public void testTwoSuccessesSameKey() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 34, HystrixEventType.SUCCESS);\n        executions.add(foo1);\n        executions.add(foo2);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23,34]}]\", actual);\n    }\n\n    @Test\n    public void testTwoSuccessesDifferentKey() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> bar1 = new SimpleExecution(barKey, 34, HystrixEventType.SUCCESS);\n        executions.add(foo1);\n        executions.add(bar1);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertTrue(actual.equals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23]},{\\\"name\\\":\\\"Bar\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[34]}]\") ||\n                actual.equals(\"[{\\\"name\\\":\\\"Bar\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[34]},{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23]}]\"));\n    }\n\n    @Test\n    public void testTwoFailuresSameKey() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 56, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        executions.add(foo1);\n        executions.add(foo2);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[56,67]}]\", actual);\n    }\n\n    @Test\n    public void testTwoSuccessesOneFailureSameKey() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 10, HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS);\n        HystrixInvokableInfo<Integer> foo3 = new SimpleExecution(fooKey, 11, HystrixEventType.SUCCESS);\n        executions.add(foo1);\n        executions.add(foo2);\n        executions.add(foo3);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertTrue(actual.equals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[10,11]},{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[67]}]\") ||\n                actual.equals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"FAILURE\\\",\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[67]},{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[10,11]}]\"));\n    }\n\n    @Test\n    public void testSingleResponseFromCache() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, \"cacheKeyA\", HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, \"cacheKeyA\");\n        executions.add(foo1);\n        executions.add(cachedFoo1);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23],\\\"cached\\\":1}]\", actual);\n    }\n\n    @Test\n    public void testMultipleResponsesFromCache() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, \"cacheKeyA\", HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, \"cacheKeyA\");\n        HystrixInvokableInfo<Integer> anotherCachedFoo1 = new SimpleExecution(fooKey, \"cacheKeyA\");\n        executions.add(foo1);\n        executions.add(cachedFoo1);\n        executions.add(anotherCachedFoo1);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23],\\\"cached\\\":2}]\", actual);\n    }\n\n    @Test\n    public void testMultipleCacheKeys() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, \"cacheKeyA\", HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, \"cacheKeyA\");\n        HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, \"cacheKeyB\", HystrixEventType.SUCCESS);\n        HystrixInvokableInfo<Integer> cachedFoo2 = new SimpleExecution(fooKey, \"cacheKeyB\");\n        executions.add(foo1);\n        executions.add(cachedFoo1);\n        executions.add(foo2);\n        executions.add(cachedFoo2);\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertTrue(actual.equals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[67],\\\"cached\\\":1},{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23],\\\"cached\\\":1}]\") ||\n                actual.equals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[23],\\\"cached\\\":1},{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[67],\\\"cached\\\":1}]\"));\n    }\n\n    @Test\n    public void testSingleSuccessMultipleEmits() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[{\\\"name\\\":\\\"EMIT\\\",\\\"count\\\":3},\\\"SUCCESS\\\"],\\\"latencies\\\":[100]}]\", actual);\n    }\n\n    @Test\n    public void testSingleSuccessMultipleEmitsAndFallbackEmits() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[{\\\"name\\\":\\\"EMIT\\\",\\\"count\\\":3},\\\"FAILURE\\\",{\\\"name\\\":\\\"FALLBACK_EMIT\\\",\\\"count\\\":2},\\\"FALLBACK_SUCCESS\\\"],\\\"latencies\\\":[100]}]\", actual);\n    }\n\n    @Test\n    public void testCollapsedBatchOfOne() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 53, collapserKey, 1, HystrixEventType.SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[53],\\\"collapsed\\\":{\\\"name\\\":\\\"FooCollapser\\\",\\\"count\\\":1}}]\", actual);\n    }\n\n    @Test\n    public void testCollapsedBatchOfSix() throws IOException {\n        List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>();\n        executions.add(new SimpleExecution(fooKey, 53, collapserKey, 6, HystrixEventType.SUCCESS));\n        HystrixRequestEvents request = new HystrixRequestEvents(executions);\n        String actual = SerialHystrixRequestEvents.toJsonString(request);\n        assertEquals(\"[{\\\"name\\\":\\\"Foo\\\",\\\"events\\\":[\\\"SUCCESS\\\"],\\\"latencies\\\":[53],\\\"collapsed\\\":{\\\"name\\\":\\\"FooCollapser\\\",\\\"count\\\":6}}]\", actual);\n    }\n\n    private class SimpleExecution implements HystrixInvokableInfo<Integer> {\n        private final HystrixCommandKey commandKey;\n        private final ExecutionResult executionResult;\n        private final String cacheKey;\n        private final HystrixCollapserKey collapserKey;\n\n        public SimpleExecution(HystrixCommandKey commandKey, int latency, HystrixEventType... events) {\n            this.commandKey = commandKey;\n            this.executionResult = ExecutionResult.from(events).setExecutionLatency(latency);\n            this.cacheKey = null;\n            this.collapserKey = null;\n        }\n\n        public SimpleExecution(HystrixCommandKey commandKey, int latency, String cacheKey, HystrixEventType... events) {\n            this.commandKey = commandKey;\n            this.executionResult = ExecutionResult.from(events).setExecutionLatency(latency);\n            this.cacheKey = cacheKey;\n            this.collapserKey = null;\n        }\n\n        public SimpleExecution(HystrixCommandKey commandKey, String cacheKey) {\n            this.commandKey = commandKey;\n            this.executionResult = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE);\n            this.cacheKey = cacheKey;\n            this.collapserKey = null;\n        }\n\n        public SimpleExecution(HystrixCommandKey commandKey, int latency, HystrixCollapserKey collapserKey, int batchSize, HystrixEventType... events) {\n            this.commandKey = commandKey;\n            ExecutionResult interimResult = ExecutionResult.from(events).setExecutionLatency(latency);\n            for (int i = 0; i < batchSize; i++) {\n                interimResult = interimResult.addEvent(HystrixEventType.COLLAPSED);\n            }\n            this.executionResult = interimResult;\n            this.cacheKey = null;\n            this.collapserKey = collapserKey;\n        }\n\n        @Override\n        public HystrixCommandGroupKey getCommandGroup() {\n            return groupKey;\n        }\n\n        @Override\n        public HystrixCommandKey getCommandKey() {\n            return commandKey;\n        }\n\n        @Override\n        public HystrixThreadPoolKey getThreadPoolKey() {\n            return threadPoolKey;\n        }\n\n        @Override\n        public String getPublicCacheKey() {\n            return cacheKey;\n        }\n\n        @Override\n        public HystrixCollapserKey getOriginatingCollapserKey() {\n            return collapserKey;\n        }\n\n        @Override\n        public HystrixCommandMetrics getMetrics() {\n            return null;\n        }\n\n        @Override\n        public HystrixCommandProperties getProperties() {\n            return null;\n        }\n\n        @Override\n        public boolean isCircuitBreakerOpen() {\n            return false;\n        }\n\n        @Override\n        public boolean isExecutionComplete() {\n            return true;\n        }\n\n        @Override\n        public boolean isExecutedInThread() {\n            return false; //do i want this?\n        }\n\n        @Override\n        public boolean isSuccessfulExecution() {\n            return executionResult.getEventCounts().contains(HystrixEventType.SUCCESS);\n        }\n\n        @Override\n        public boolean isFailedExecution() {\n            return executionResult.getEventCounts().contains(HystrixEventType.FAILURE);\n        }\n\n        @Override\n        public Throwable getFailedExecutionException() {\n            return null;\n        }\n\n        @Override\n        public boolean isResponseFromFallback() {\n            return executionResult.getEventCounts().contains(HystrixEventType.FALLBACK_SUCCESS);\n        }\n\n        @Override\n        public boolean isResponseTimedOut() {\n            return executionResult.getEventCounts().contains(HystrixEventType.TIMEOUT);\n        }\n\n        @Override\n        public boolean isResponseShortCircuited() {\n            return executionResult.getEventCounts().contains(HystrixEventType.SHORT_CIRCUITED);\n        }\n\n        @Override\n        public boolean isResponseFromCache() {\n            return executionResult.getEventCounts().contains(HystrixEventType.RESPONSE_FROM_CACHE);\n        }\n\n        @Override\n        public boolean isResponseRejected() {\n            return executionResult.isResponseRejected();\n        }\n\n        @Override\n        public boolean isResponseSemaphoreRejected() {\n            return executionResult.getEventCounts().contains(HystrixEventType.SEMAPHORE_REJECTED);\n        }\n\n        @Override\n        public boolean isResponseThreadPoolRejected() {\n            return executionResult.getEventCounts().contains(HystrixEventType.THREAD_POOL_REJECTED);\n        }\n\n        @Override\n        public List<HystrixEventType> getExecutionEvents() {\n            return executionResult.getOrderedList();\n        }\n\n        @Override\n        public int getNumberEmissions() {\n            return executionResult.getEventCounts().getCount(HystrixEventType.EMIT);\n        }\n\n        @Override\n        public int getNumberFallbackEmissions() {\n            return executionResult.getEventCounts().getCount(HystrixEventType.FALLBACK_EMIT);\n        }\n\n        @Override\n        public int getNumberCollapsed() {\n            return executionResult.getEventCounts().getCount(HystrixEventType.COLLAPSED);\n        }\n\n        @Override\n        public int getExecutionTimeInMilliseconds() {\n            return executionResult.getExecutionLatency();\n        }\n\n        @Override\n        public long getCommandRunStartTimeInNanos() {\n            return System.currentTimeMillis();\n        }\n\n        @Override\n        public ExecutionResult.EventCounts getEventCounts() {\n            return executionResult.getEventCounts();\n        }\n\n        @Override\n        public String toString() {\n            return \"SimpleExecution{\" +\n                    \"commandKey=\" + commandKey.name() +\n                    \", executionResult=\" + executionResult +\n                    \", cacheKey='\" + cacheKey + '\\'' +\n                    \", collapserKey=\" + collapserKey +\n                    '}';\n        }\n    }\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name='hystrix'\ninclude 'hystrix-core', \\\n'hystrix-examples', \\\n'hystrix-examples-webapp', \\\n'hystrix-contrib/hystrix-clj', \\\n'hystrix-contrib/hystrix-request-servlet', \\\n'hystrix-contrib/hystrix-servo-metrics-publisher', \\\n'hystrix-contrib/hystrix-metrics-event-stream', \\\n'hystrix-contrib/hystrix-metrics-event-stream-jaxrs', \\\n'hystrix-contrib/hystrix-rx-netty-metrics-stream', \\\n'hystrix-contrib/hystrix-codahale-metrics-publisher', \\\n'hystrix-contrib/hystrix-yammer-metrics-publisher', \\\n'hystrix-contrib/hystrix-network-auditor-agent', \\\n'hystrix-contrib/hystrix-javanica', \\\n'hystrix-contrib/hystrix-junit', \\\n'hystrix-serialization'\n\nproject(':hystrix-contrib/hystrix-clj').name = 'hystrix-clj'\nproject(':hystrix-contrib/hystrix-request-servlet').name = 'hystrix-request-servlet'\nproject(':hystrix-contrib/hystrix-servo-metrics-publisher').name = 'hystrix-servo-metrics-publisher'\nproject(':hystrix-contrib/hystrix-metrics-event-stream').name = 'hystrix-metrics-event-stream'\nproject(':hystrix-contrib/hystrix-metrics-event-stream-jaxrs').name = 'hystrix-metrics-event-stream-jaxrs'\nproject(':hystrix-contrib/hystrix-rx-netty-metrics-stream').name = 'hystrix-rx-netty-metrics-stream'\nproject(':hystrix-contrib/hystrix-codahale-metrics-publisher').name = 'hystrix-codahale-metrics-publisher'\nproject(':hystrix-contrib/hystrix-yammer-metrics-publisher').name = 'hystrix-yammer-metrics-publisher'\nproject(':hystrix-contrib/hystrix-network-auditor-agent').name = 'hystrix-network-auditor-agent'\nproject(':hystrix-contrib/hystrix-javanica').name = 'hystrix-javanica'\nproject(':hystrix-contrib/hystrix-junit').name = 'hystrix-junit'\n"
  }
]