{@inheritdoc}

@throws Exception
@throws CacheException
171486
public function getAvailableTransitions(Workflow $workflow, AbstractSubject $subject, array $metaData = null): Generator
    {
        if (!$workflow instanceof StateMachine) {
            throw new Exception(sprintf('Generator %s only support model type state machine', static::getName()));
        }

        $graph = $this->graphBuilder->build($workflow);
        $components = new ConnectedComponents($graph);
        $singleComponent = $components->isSingle();
        if ($singleComponent) {
            $algorithm = new Eulerian($graph);
            $startVertex = $graph->getVertex(VertexHelper::getId([$workflow->getDefinition()->getInitialPlace()]));
            $edges = $algorithm->getEdges($startVertex);
            $edges = $edges->getVector();
            while (!empty($edges)) {
                $edge = array_shift($edges);
                $transitionName = $edge->getAttribute('name');
                if ($workflow->can($subject, $transitionName)) {
                    yield $transitionName;
                } else {
                    break;
                }
            }
        }
    }
2126
private function cache(string $key, string $value, int $cacheTime = null)
    {
        try {
            $this->client->set($key, $value);

            if ($cacheTime !== null) {
                $this->client->expire($key, $cacheTime);
            }
        } catch (\Exception $e) {
            // We don't want exceptions in accessing the cache to break functionality.
            // The cache should be as transparent as possible.
            // If insight is needed into these exceptions,
            // a better way would be by notifying an observer with the errors.
        }
    }
1058972
public function setItem($cacheId, $content)
    {
        $cacheId = $this->normalizeKey($cacheId);

        /** @var $cache \Zend\Cache\Storage\Adapter\AbstractAdapter */
        $cache = $this->cache;

        if (!$cache->hasPlugin(new Serializer())) {
            $content = serialize($content);
        }

        try {
            return $cache->setItem($cacheId, $content);
        } catch (ZendException\ExceptionInterface $ex) {
            return false;
        }
    }
277122
public void rebuild() throws Exception
    {
        Preconditions.checkState(!executorService.isShutdown(), "cache has been closed");

        ensurePath();

        clear();

        List<String> children = client.getChildren().forPath(path);
        for ( String child : children )
        {
            String fullPath = ZKPaths.makePath(path, child);
            internalRebuildNode(fullPath);

            if ( rebuildTestExchanger != null )
            {
                rebuildTestExchanger.exchange(new Object());
            }
        }

        // this is necessary so that any updates that occurred while rebuilding are taken
        offerOperation(new RefreshOperation(this, RefreshMode.FORCE_GET_DATA_AND_STAT));
    }
1001624
public void _doInclude(PageSource[] sources, boolean runOnce, Object cachedWithin) throws PageException {
	if (cachedWithin == null) {
	    _doInclude(sources, runOnce);
	    return;
	}

	// ignore call when runonce an it is not first call
	if (runOnce) {
	    Page currentPage = PageSourceImpl.loadPage(this, sources);
	    if (runOnce && includeOnce.contains(currentPage.getPageSource())) return;
	}

	// get cached data
	String cacheId = CacheHandlerCollectionImpl.createId(sources);
	CacheHandler cacheHandler = config.getCacheHandlerCollection(Config.CACHE_TYPE_INCLUDE, null).getInstanceMatchingObject(cachedWithin, null);

	if (cacheHandler instanceof CacheHandlerPro) {

	    CacheItem cacheItem = ((CacheHandlerPro) cacheHandler).get(this, cacheId, cachedWithin);

	    if (cacheItem instanceof IncludeCacheItem) {
		try {
		    write(((IncludeCacheItem) cacheItem).getOutput());
		    return;
		}
		catch (IOException e) {
		    throw Caster.toPageException(e);
		}
	    }
	}
	else if (cacheHandler != null) { // TODO this else block can be removed when all cache handlers implement CacheHandlerPro

	    CacheItem cacheItem = cacheHandler.get(this, cacheId);

	    if (cacheItem instanceof IncludeCacheItem) {
		try {
		    write(((IncludeCacheItem) cacheItem).getOutput());
		    return;
		}
		catch (IOException e) {
		    throw Caster.toPageException(e);
		}
	    }
	}

	// cached item not found, process and cache result if needed
	long start = System.nanoTime();
	BodyContent bc = pushBody();

	try {
	    _doInclude(sources, runOnce);
	    String out = bc.getString();

	    if (cacheHandler != null) {
		CacheItem cacheItem = new IncludeCacheItem(out, ArrayUtil.isEmpty(sources) ? null : sources[0], System.nanoTime() - start);
		cacheHandler.set(this, cacheId, cachedWithin, cacheItem);
		return;
	    }
	}
	finally {
	    BodyContentUtil.flushAndPop(this, bc);
	}
    }
1345765
public function set($data) {
// 		debug('FSCache set', $data);
// 		debug('FSCache path '.$this->path, $this->editTime.static::$delim.serialize($data));
		try {
			return file_put_contents($this->path, $this->editTime.static::$delim.serialize($data));
		} catch( Exception $e ) {
			throw new CacheException($e->getMessage(), $e->getCode(), $e);
		}
	}
1298653
public boolean isCacheable(ExCache cache, Object target, Object[] arguments, Object result) throws Exception {
        if (null == cache || cache.expire() < 0 || cache.key().length() == 0) {
            return false;
        }
        boolean rv = true;
        if (null != cache.condition() && cache.condition().length() > 0) {
            rv = this.getElValue(cache.condition(), target, arguments, result, true, Boolean.class);
        }
        return rv;
    }
1150082
public function setCache($cache)
    {
        $this->cache = $cache;
        if ($this->isBool($cache) && $cache === false) {
            $this->cache = $cache;
        } else {
            if (is_object($cache)) {
                if ($this->isInstanceOf($cache, CacheStorage::class)) {
                    $this->cache = $cache;
                } else {
                    throw new RouterException('$cache must either be a boolean or instance of ' . CacheStorage::class . '.');
                }
            } else {
                $this->cache = $this->cache($cache);
            }
        }
    }
1141899
@Override
    protected T readCacheDataFromFile(File file) throws CacheLoadingException {
        try {
            JsonParser jsonParser = jsonFactory.createJsonParser(new FileReader(file));
            T result = jsonParser.parse(getHandledClass(), null);
            jsonParser.close();
            return result;
        } catch (FileNotFoundException e) {
            // Should not occur (we test before if file exists)
            // Do not throw, file is not cached
            Ln.w("file " + file.getAbsolutePath() + " does not exists", e);
            return null;
        } catch (Exception e) {
            throw new CacheLoadingException(e);
        }
    }
1183961
final public function prepare_to_cache() {
        $result = array();
        foreach ($this as $key => $value) {
            if ($value instanceof cacheable_object) {
                $value = new cache_cached_object($value);
            } else {
                throw new coding_exception('Only cacheable_object instances can be added to a cacheable_array');
            }
            $result[$key] = $value;
        }
        return $result;
    }
636999
public function get(ContextInterface $context, string $path): ViewInterface
    {
        if (!$this->has($context, $path)) {
            throw new CacheException("No cache is available for {$path}.");
        }

        return $this->cache[$context->getID()][$path];
    }
375137
@Override
  public V get(K k) throws ExecutionException {
    V value = getIfPresent(k);
    if (null == value) {
      try {
        value = cacheLoader.load(k);
        if (null != value) {
          put(k, value);
        }
      } catch (Exception e) {
        LOGGER.warn("Failed to load value for the cache {}", e);
      }
    }
    //LOGGER.debug("get {} = {}", k, value);
    return value;
  }
94807
@Override
    public void afterPropertiesSet() throws Exception {
        if (this.cacheKeyGenerator == null) {
            final AttributeBasedCacheKeyGenerator cacheKeyGenerator = new AttributeBasedCacheKeyGenerator();
            cacheKeyGenerator.setCacheKeyAttributes(this.cacheKeyAttributes);

            final IUsernameAttributeProvider usernameAttributeProvider = this.getUsernameAttributeProvider();
            final String usernameAttribute = usernameAttributeProvider.getUsernameAttribute();
            cacheKeyGenerator.setDefaultAttributeName(usernameAttribute);
            this.cacheKeyGenerator = cacheKeyGenerator;
        }
    }
306905
public Cache createCache(String name) throws CacheException {
		SynchronizedCacheConfiguration config = new SynchronizedCacheConfiguration();
		return createCache(name, config, Cache.SYN_CACHE);
	}
1123347
public void setCache(String cacheName, String cacheKey, Object object) {
        Cache cache = cacheManager.getCache(cacheName);
        if (cache == null) {
            return;
        }
        cache.put(new Element(cacheKey, object));
    }
402735
public void run() throws Exception {

        CmsObject cms = getCmsObject();
        String seoFilePath = cms.getRequestContext().getUri();
        CmsResource seoFile = cms.readResource(seoFilePath);
        m_configuration = new CmsXmlSeoConfiguration();
        m_configuration.load(cms, seoFile);
        String mode = m_configuration.getMode();
        if (mode.equals(CmsXmlSeoConfiguration.MODE_ROBOTS_TXT)) {
            showRobotsTxt();
        } else {
            boolean updateCache = Boolean.parseBoolean(getRequest().getParameter("updateCache"));
            String value = "";
            if (updateCache && m_configuration.usesCache()) {
                // update request, and caching is configured -> update the cache
                CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration);
                value = generator.renderSitemap();
                CmsXmlSitemapCache.INSTANCE.put(seoFile.getRootPath(), value);
            } else if (!updateCache && m_configuration.usesCache()) {
                // normal request, and caching is configured -> look in the cache first, and if not found, calculate sitemap and store it in cache
                String cachedValue = CmsXmlSitemapCache.INSTANCE.get(seoFile.getRootPath());
                if (cachedValue != null) {
                    value = cachedValue;
                } else {
                    CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration);
                    value = generator.renderSitemap();
                    CmsXmlSitemapCache.INSTANCE.put(seoFile.getRootPath(), value);
                }
            } else if (!updateCache && !m_configuration.usesCache()) {
                // normal request, caching is not configured -> always generate a fresh sitemap
                CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration);
                value = generator.renderSitemap();
            } else if (updateCache && !m_configuration.usesCache()) {
                // update request with no caching configured -> ignore
            }
            getResponse().getWriter().print(value);
        }

    }
1204477
function cacheService(cacheServiceConfig, cacheModules) {
  var self = this;

  /**
   ******************************************* PUBLIC FUNCTIONS *******************************************
   */

  /**
   * Get the value associated with a given key
   * @param {string} key
   * @param {function} cb
   */
  self.get = function(key, cb){
    if(arguments.length < 2){
      throw new Exception('INCORRECT_ARGUMENT_EXCEPTION', '.get() requires 2 arguments.');
    }

    log(false, '.get() called:', {key: key});
    var curCache;
    var curCacheIndex = 0;

    var callback = function(err, result){
      var status = checkCacheResponse(key, err, result, curCache.type, curCacheIndex - 1);
      if(status.status === 'continue'){
        if(status.toIndex){
          curCacheIndex = status.toIndex;
        }
        getNextCache();
        return;
      }
      if(status.status === 'break'){
        cb(err, status.result);
        if(self.writeToVolatileCaches){
          writeToVolatileCaches(curCacheIndex - 1, key, result);
        }
      }
      else {
        log(false, '.get() key not found:', {key: key});
        cb(null, null);
      }
    };

    function getNextCache(){
      if(curCacheIndex < self.caches.length){
        curCache = self.caches[curCacheIndex++];
        curCache.get(key, callback);
      }
    }

    getNextCache();
  };

  /**
   * Get multiple values given multiple keys
   * @param {array} keys
   * @param {function} cb
   */
  self.mget = function(keys, cb){
    if(arguments.length < 2){
      throw new Exception('INCORRECT_ARGUMENT_EXCEPTION', '.mget() requires 2 arguments.');
    }
    log(false, '.mget() called:', {keys: keys});
    var maxKeysFound = 0;
    var returnError = null;
    var returnResponse = null;
    var keepGoing = true;
    var i = 0;
    var successIndex = 0;
    var finished = false;
    var finish = function(index){
      if(!finished){
        finished = true;
        keepGoing = false;
        if(self.writeToVolatileCaches){
          writeToVolatileCaches(index, returnResponse);
        }
        cb(returnError, returnResponse);
      }
    };
    var callback = function(err, response, index){
      var objectSize = 0;
      for (var key in response){
        if(response.hasOwnProperty(key)){
          ++objectSize;
        }
      }
      if(objectSize === keys.length){
        returnResponse = response;
        finish(index);
      }
      else if(objectSize > maxKeysFound){
        maxKeysFound = objectSize;
        returnResponse = response;
        successIndex = index;
      }
      if(index + 1 === self.caches.length){
        returnResponse = response;
        finish(successIndex);
      }
    };
    while(keepGoing && i < self.caches.length){
      var cache = self.caches[i];
      cache.mget(keys, callback, i);
      i++;
    }
  };

  /**
   * Associate a key and value and optionally set an expiration
   * @param {string} key
   * @param {string | object} value
   * @param {integer} expiration
   * @param {function} refresh
   * @param {function} cb
   */
  self.set = function(){
    if(arguments.length < 2){
      throw new Exception('INCORRECT_ARGUMENT_EXCEPTION', '.set() requires a minimum of 2 arguments.');
    }
    var key = arguments[0];
    var value = arguments[1];
    var expiration = arguments[2] || null;
    var refresh = arguments[3] || null;
    var cb = arguments[4] || noop;
    if(arguments.length === 4 && typeof arguments[3] === 'function'){
      cb = arguments[3];
      if(typeof arguments[2] === 'function'){
        refresh = arguments[2];
        expiration = null;
      }
      else{
        expiration = arguments[2];
        refresh = null;
      }
    }
    else if(arguments.length === 3 && typeof arguments[2] === 'function'){
      cb = arguments[2];
      expiration = null;
    }
    log(false, '.set() called:', {key: key, value: value});
    for(var i = 0; i < self.cachesLength; i++){
      var cache = self.caches[i];
      var ref = (i === self.caches.length - 1) ? refresh : null;
      var func = (i === 0) ? cb : noop;
      cache.set(key, value, expiration, ref, func);
    }
  };

  /**
   * Associate multiple keys with multiple values and optionally set expirations per function and/or key
   * @param {object} arguments[0]
   * @param {integer} arguments[1]
   * @param {function} arguments[2]
   */
  self.mset = function(){
    if(arguments.length < 1){
      throw new Exception('INCORRECT_ARGUMENT_EXCEPTION', '.mset() requires a minimum of 1 argument.');
    }
    var obj = arguments[0];
    var expiration = arguments[1] || null;
    var cb = arguments[2] || null;
    log(false, '.mset() called:', {data: obj});
    for(var i = 0; i < self.cachesLength; i++){
      var cache = self.caches[i];
      expiration = expiration || cache.expiration;
      if(i === self.caches.length - 1){
        cache.mset(obj, expiration, cb);
      }
      else{
        cache.mset(obj, expiration);
      }
    }
  };

  /**
   * Delete a list of keys and their values
   * @param {array} keys
   * @param {function} cb
   */
  self.del = function(keys, cb){
    if(arguments.length < 1){
      throw new Exception('INCORRECT_ARGUMENT_EXCEPTION', '.del() requires a minimum of 1 argument.');
    }
    log(false, '.del() called:', {keys: keys});
    for(var i = 0; i < self.cachesLength; i++){
      var cache = self.caches[i];
      if(i === self.caches.length - 1){
        cache.del(keys, cb);
      }
      else{
        cache.del(keys);
      }
    }
  };

  /**
   * Flush all keys and values from all configured caches in caches
   * @param {function} cb
   */
  self.flush = function(cb){
    log(false, '.flush() called');
    for(var i = 0; i < self.cachesLength; i++){
      var cache = self.caches[i];
      if(i === self.caches.length - 1){
        cache.flush(cb);
      }
      else{
        cache.flush();
      }
    }
  };

  /**
   ******************************************* PRIVATE FUNCTIONS *******************************************
   */

  /**
   * Initialize cacheService given the provided constructor params
   */
  function init(){
    if(!cacheServiceConfig) {
      cacheServiceConfig = {};
    }
    self.nameSpace = cacheServiceConfig.nameSpace || '';
    self.verbose = (typeof cacheServiceConfig.verbose === 'boolean') ? cacheServiceConfig.verbose : false;
    self.writeToVolatileCaches = (typeof cacheServiceConfig.writeToVolatileCaches === 'boolean') ? cacheServiceConfig.writeToVolatileCaches : true;
    self.caches = new CacheCollection({nameSpace: self.nameSpace, verbose: self.verbose}, cacheModules).caches;
    self.cachesLength = self.caches.length;
  }

  /**
   * Decides what action cacheService should take given the response from a configured cache
   * @param {string} key
   * @param {null | object} err
   * @param {null | object | string} result
   * @param {string} type
   * @param {integer} cacheIndex
   */
  function checkCacheResponse(key, err, result, type, cacheIndex){
    if(err){
      log(true, 'Error when getting key ' + key + ' from cache of type ' + type + ':', err);

      if(cacheIndex < self.caches.length - 1){
        return {status:'continue'};
      }
    }
    //THIS ALLOWS false AS A VALID CACHE VALUE, BUT DO I WANT null TO BE VALID AS WELL?
    if(result !== null && typeof result !== 'undefined'){
      log(false, 'Key found:', {key: key, value: result});
      return {status: 'break', result: result};
    }
    var curCache = self.caches[cacheIndex];
    for(var i = cacheIndex + 1; i < self.cachesLength; i++) {
      var nextCache = self.caches[i];
      if(nextCache.checkOnPreviousEmpty || nextCache.expiration > curCache.expiration){
        return {status:'continue', toIndex: i};
      }
    }
    return {status: 'else'};
  }

  /**
   * Writes data to caches that appear before the current cache in caches
   * @param {integer} currentCacheIndex
   * @param {string} key
   * @param {null | object | string} value
   */
  function writeToVolatileCaches(currentCacheIndex, key, value){
    if(currentCacheIndex > 0){
      var curExpiration = self.caches[currentCacheIndex].expiration;
      for(var tempIndex = currentCacheIndex; tempIndex > -1; tempIndex--){
        var preExpiration = self.caches[tempIndex].expiration;
        if(preExpiration <= curExpiration){
          var preCache = self.caches[currentCacheIndex];
          if(value){
            preCache.set(key, value); /*This means that a more volatile cache can have a key longer than a less volatile cache. Should I adjust this?*/
          }
          else if(typeof key === 'object'){
            preCache.mset(key);
          }
        }
      }
    }
  }

  /**
   * Instantates an exception to be thrown
   * @param {string} name
   * @param {string} message
   * @return {exception}
   */
  function Exception(name, message) {
    this.name = name;
    this.message = message;
  }

  /**
   * Logging utility function
   * @param {boolean} isError
   * @param {string} message
   * @param {object} data
   */
  function log(isError, message, data){
    var indentifier = 'cacheService: ';
    if(self.verbose || isError){
      if(data) {
        console.log(indentifier + message, data);
      } else {
        console.log(indentifier + message);
      }
    }
  }

  function noop(){}

  init();
}