/**
  * @param underlying The provider to wrap
  * @param manager The cache manager
  */
 public EHCachingSecurityMasterDetailProvider(
     SecurityMasterDetailProvider underlying, CacheManager manager) {
   super();
   _underlying = underlying;
   _manager = manager;
   EHCacheUtils.addCache(_manager, SECURITY_CACHE);
   _detailsCache = EHCacheUtils.getCacheFromManager(_manager, SECURITY_CACHE);
 }
  /**
   * Creates an instance over an underlying source specifying the cache manager.
   *
   * @param underlying the underlying security source, not null
   * @param cacheManager the cache manager, not null
   */
  public AbstractEHCachingSourceWithExternalBundle(
      final S underlying, final CacheManager cacheManager) {
    super(underlying, cacheManager);
    EHCacheUtils.addCache(cacheManager, this.getClass().getName() + EID_TO_UID_CACHE);
    _eidToUidCache =
        EHCacheUtils.getCacheFromManager(
            cacheManager, this.getClass().getName() + EID_TO_UID_CACHE);

    // this is crude but it allows caching of lookups that use VersionCorrection.LATEST.
    // VersionCorrection.LATEST can refer to different versions of the same object, but by clearing
    // the caches
    // when anything in the underlying source changes we ensure we never see stale data.
    // this won't work well if the data changes frequently.
    getUnderlying()
        .changeManager()
        .addChangeListener(
            new ChangeListener() {
              @Override
              public void entityChanged(ChangeEvent event) {
                _eidToUidCache.flush();
              }
            });
  }
  private Future<?> executeTestJob(DependencyGraphExecutorFactory<?> factory) {
    final InMemoryLKVMarketDataProvider marketDataProvider = new InMemoryLKVMarketDataProvider();
    final MarketDataProviderResolver marketDataProviderResolver =
        new SingleMarketDataProviderResolver(
            new SingletonMarketDataProviderFactory(marketDataProvider));
    final InMemoryFunctionRepository functionRepository = new InMemoryFunctionRepository();
    _functionCount.set(0);
    final MockFunction mockFunction =
        new MockFunction(new ComputationTarget("Foo")) {

          @Override
          public Set<ComputedValue> execute(
              FunctionExecutionContext executionContext,
              FunctionInputs inputs,
              ComputationTarget target,
              Set<ValueRequirement> desiredValues) {
            try {
              Thread.sleep(JOB_FINISH_TIME / (JOB_SIZE * 2));
            } catch (InterruptedException e) {
              throw new OpenGammaRuntimeException("Function interrupted", e);
            }
            _functionCount.incrementAndGet();
            return super.execute(executionContext, inputs, target, desiredValues);
          }
        };
    functionRepository.addFunction(mockFunction);
    final FunctionCompilationContext compilationContext = new FunctionCompilationContext();
    final CompiledFunctionService compilationService =
        new CompiledFunctionService(
            functionRepository, new CachingFunctionRepositoryCompiler(), compilationContext);
    compilationService.initialize();
    final FunctionResolver functionResolver = new DefaultFunctionResolver(compilationService);
    final MockSecuritySource securitySource = new MockSecuritySource();
    final MockPositionSource positionSource = new MockPositionSource();
    final ViewComputationCacheSource computationCacheSource =
        new InMemoryViewComputationCacheSource(FudgeContext.GLOBAL_DEFAULT);
    final FunctionInvocationStatisticsGatherer functionInvocationStatistics =
        new DiscardingInvocationStatisticsGatherer();
    final ViewProcessorQueryReceiver viewProcessorQueryReceiver = new ViewProcessorQueryReceiver();
    final ViewProcessorQuerySender viewProcessorQuerySender =
        new ViewProcessorQuerySender(InMemoryRequestConduit.create(viewProcessorQueryReceiver));
    final FunctionExecutionContext executionContext = new FunctionExecutionContext();
    final ComputationTargetResolver targetResolver =
        new DefaultComputationTargetResolver(securitySource, positionSource);
    final JobDispatcher jobDispatcher =
        new JobDispatcher(
            new LocalNodeJobInvoker(
                new LocalCalculationNode(
                    computationCacheSource,
                    compilationService,
                    executionContext,
                    targetResolver,
                    viewProcessorQuerySender,
                    Executors.newCachedThreadPool(),
                    functionInvocationStatistics)));
    final ViewPermissionProvider viewPermissionProvider = new DefaultViewPermissionProvider();
    final GraphExecutorStatisticsGathererProvider graphExecutorStatisticsProvider =
        new DiscardingGraphStatisticsGathererProvider();

    ViewDefinition viewDefinition = new ViewDefinition("TestView", UserPrincipal.getTestUser());
    viewDefinition.addViewCalculationConfiguration(
        new ViewCalculationConfiguration(viewDefinition, "default"));
    MockViewDefinitionRepository viewDefinitionRepository = new MockViewDefinitionRepository();
    viewDefinitionRepository.addDefinition(viewDefinition);

    final ViewProcessContext vpc =
        new ViewProcessContext(
            viewDefinitionRepository,
            viewPermissionProvider,
            marketDataProviderResolver,
            compilationService,
            functionResolver,
            positionSource,
            securitySource,
            new DefaultCachingComputationTargetResolver(
                new DefaultComputationTargetResolver(securitySource, positionSource),
                EHCacheUtils.createCacheManager()),
            computationCacheSource,
            jobDispatcher,
            viewProcessorQueryReceiver,
            factory,
            graphExecutorStatisticsProvider);
    final DependencyGraph graph = new DependencyGraph("Default");
    DependencyNode previous = null;
    for (int i = 0; i < JOB_SIZE; i++) {
      DependencyNode node = new DependencyNode(new ComputationTarget("Foo"));
      node.setFunction(mockFunction);
      if (previous != null) {
        node.addInputNode(previous);
      }
      graph.addDependencyNode(node);
      previous = node;
    }
    final Map<String, DependencyGraph> graphs = new HashMap<String, DependencyGraph>();
    graphs.put(graph.getCalculationConfigurationName(), graph);
    CompiledViewDefinitionWithGraphsImpl viewEvaluationModel =
        new CompiledViewDefinitionWithGraphsImpl(
            viewDefinition, graphs, new SimplePortfolio("Test Portfolio"), 0);
    ViewCycleExecutionOptions cycleOptions = new ViewCycleExecutionOptions();
    cycleOptions.setValuationTime(Instant.ofEpochMillis(1));
    cycleOptions.setMarketDataSpecification(new MarketDataSpecification());
    final SingleComputationCycle cycle =
        new SingleComputationCycle(
            UniqueId.of("Test", "Cycle1"),
            UniqueId.of("Test", "ViewProcess1"),
            vpc,
            viewEvaluationModel,
            cycleOptions,
            VersionCorrection.of(Instant.ofEpochMillis(1), Instant.ofEpochMillis(1)));
    return cycle.getDependencyGraphExecutor().execute(graph, cycle.getStatisticsGatherer());
  }