class Cache implements Ehcache, StoreListener {

    public void initialise() {
        synchronized (this) {
            if (!status.equals(Status.STATUS_UNINITIALISED)) {
                throw new IllegalStateException("Cannot initialise the " + configuration.getName()
                        + " cache because its status is not STATUS_UNINITIALISED");
            }

            if (configuration.getMaxElementsInMemory() == 0) {
                LOG.warn("Cache: " + configuration.getName() +
                        " has a maxElementsInMemory of 0.  " +
                        "In Ehcache 2.0 this has been changed to mean a store" +
                        " with no capacity limit. Set it to 1 if you want" +
                        " no elements cached in memory");
            }

            CopyStrategy copyStrategy = null;
            if (configuration.getTransactionalMode().isTransactional() && !configuration.isXaTransactional()) {
                copyStrategy = configuration.getCopyStrategyConfiguration().getCopyStrategyInstance();
                configuration.getCopyStrategyConfiguration().setCopyStrategyInstance(new ImmutableValueElementCopyStrategy());
            }

            if (configuration.getTransactionalMode().isTransactional()
                && configuration.isTerracottaClustered()
                && configuration.getTerracottaConfiguration().getValueMode() != TerracottaConfiguration.ValueMode.SERIALIZATION) {
                throw new CacheException("To be transactional, a Terracotta clustered cache needs to be in Serialization value mode");
            }

            final Store store;
            if (configuration.isOverflowToOffHeap()) {
                try {
                    Class<Store> storeClass = ClassLoaderUtil.loadClass(OFF_HEAP_STORE_CLASSNAME);
                    try {
                        store = (Store) storeClass.getMethod("create", Ehcache.class, String.class).invoke(null, this, diskStorePath);
                    } catch (NoSuchMethodException e) {
                       throw new CacheException("Cache: " + configuration.getName() + " cannot find static factory" +
                        " method create(Ehcache, String)" +
                        " in store class " + OFF_HEAP_STORE_CLASSNAME, e);
                    } catch (InvocationTargetException e) {
                        Throwable cause = e.getCause();
                        if (cause instanceof CacheException) {
                            throw (CacheException)cause;
                        } else {
                            throw new CacheException("Cache: " + configuration.getName() +
                                    " cannot instantiate store " + OFF_HEAP_STORE_CLASSNAME, cause);
                        }
                    } catch (IllegalAccessException e) {
                        throw new CacheException("Cache: " + configuration.getName() +
                                " cannot instantiate store " + OFF_HEAP_STORE_CLASSNAME, e);
                    }
                } catch (ClassNotFoundException e) {
                    throw new CacheException("Cache " + configuration.getName() +
                            " cannot be configured because the off-heap store class could not be found. " +
                            "You must use an enterprise version of Ehcache to successfully enable overflowToOffHeap.");
                }
            } else if (isTerracottaClustered()) {
                if (!getCacheConfiguration().getTerracottaConfiguration().isStorageStrategySet()) {
                    getCacheConfiguration().getTerracottaConfiguration().storageStrategy(
                            TerracottaClusteredInstanceHelper.getDefaultStorageStrategyForCurrentRuntime());
                }
                store = cacheManager.createTerracottaStore(this);
                boolean unlockedReads = !this.configuration.getTerracottaConfiguration().getCoherentReads();
                // if coherentReads=false, make coherent=false
                boolean coherent = unlockedReads ? false : this.configuration.getTerracottaConfiguration().isCoherent();
                store.setNodeCoherent(coherent);
            } else {
                if (useClassicLru && configuration.getMemoryStoreEvictionPolicy().equals(MemoryStoreEvictionPolicy.LRU)) {
                    Store disk = createDiskStore();
                    store = new LegacyStoreWrapper(new LruMemoryStore(this, disk), disk, registeredEventListeners, configuration);
                } else {
                    if (configuration.isDiskPersistent()) {
                        store = DiskPersistentStore.create(this, diskStorePath);
                    } else if (configuration.isOverflowToDisk()) {
                        store = OverflowToDiskStore.create(this, diskStorePath);
                    } else {
                        store = MemoryOnlyStore.create(this, diskStorePath);
                    }
                }
            }

            if (configuration.isXaTransactional()) {
                TransactionManager txnManager = (TransactionManager) configuration.getDefaultTransactionManager();
                if (txnManager == null) {
                    txnManager = transactionManagerLookup.getTransactionManager();
                }
                if (txnManager == null) {
                    throw new CacheException("You've configured cache " + cacheManager.getName() + "."
                                             + configuration.getName() + " to be transactional, but no TransactionManager could be found!");
                }
                //set xa enabled
                if (configuration.isTerracottaClustered()) {
                    configuration.getTerracottaConfiguration().setCacheXA(true);
                }

                EhcacheXAStore ehcacheXAStore =
                    cacheManager.createEhcacheXAStore(this, store, txnManager instanceof SyncTransactionManager);

                // this xaresource is for initial registration and recovery
                EhcacheXAResourceImpl xaResource = new EhcacheXAResourceImpl(this, txnManager, ehcacheXAStore);
                transactionManagerLookup.register(xaResource);

                this.compoundStore = new XATransactionalStore(this, ehcacheXAStore, transactionManagerLookup, txnManager);
            } else if (configuration.isLocalJtaTransactional()) {
                SoftLockFactory softLockFactory = cacheManager.createSoftLockFactory(this);
                LocalTransactionStore localTransactionStore = new LocalTransactionStore(getCacheManager().getTransactionController(), softLockFactory, this, store, copyStrategy);
                this.compoundStore = new JtaLocalTransactionStore(localTransactionStore, transactionManagerLookup, cacheManager.getTransactionController());
            } else if (configuration.isLocalTransactional()) {
                SoftLockFactory softLockFactory = cacheManager.createSoftLockFactory(this);
                this.compoundStore = new LocalTransactionStore(getCacheManager().getTransactionController(), softLockFactory, this, store, copyStrategy);
            } else {
                this.compoundStore = store;
            }


            Map<String, AttributeExtractor> extractors = new HashMap<String, AttributeExtractor>();
            for (SearchAttribute sa : configuration.getSearchAttributes().values()) {
                extractors.put(sa.getName(), sa.constructExtractor());
            }

            store.setAttributeExtractors(extractors);


            this.cacheWriterManager = configuration.getCacheWriterConfiguration().getWriteMode().createWriterManager(this);
            initialiseCacheWriterManager(false);

            changeStatus(Status.STATUS_ALIVE);
            initialiseRegisteredCacheExtensions();
            initialiseRegisteredCacheLoaders();
            initialiseRegisteredCacheWriter();

            // initialize live statistics
            // register to get notifications of
            // put/update/removeInternal/expiry/eviction
            getCacheEventNotificationService().registerListener(liveCacheStatisticsData);
            // set up default values
            liveCacheStatisticsData.setStatisticsAccuracy(Statistics.STATISTICS_ACCURACY_BEST_EFFORT);
            liveCacheStatisticsData.setStatisticsEnabled(configuration.getStatistics());

            // register the sampled cache statistics
            this.registerCacheUsageListener(sampledCacheStatistics);

            if (isTerracottaClustered()) {
                // create this to be sure that it's present on each node to receive clustered events,
                // even if this node is not sending out its events
                cacheManager.createTerracottaEventReplicator(this);
            }

            Object context = compoundStore.getInternalContext();
            if (context instanceof CacheLockProvider) {
                lockProvider = (CacheLockProvider) context;
            }
        }

        compoundStore.addStoreListener(this);

        if (LOG.isDebugEnabled()) {
            LOG.debug("Initialised cache: " + configuration.getName());
        }

        if (disabled) {
            LOG.warn("Cache: " + configuration.getName() + " is disabled because the " + NET_SF_EHCACHE_DISABLED
                    + " property was set to true. No elements will be added to the cache.");
        }
    }

    public  Cache(CacheConfiguration cacheConfiguration);
    public  Cache(CacheConfiguration cacheConfiguration,
                 RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader);
    public  Cache(String name, int maxElementsInMemory, boolean overflowToDisk,
                 boolean eternal, long timeToLiveSeconds, long timeToIdleSeconds);
    public  Cache(String name,
                 int maxElementsInMemory,
                 boolean overflowToDisk,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds);
    public  Cache(String name,
                 int maxElementsInMemory,
                 MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
                 boolean overflowToDisk,
                 String diskStorePath,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds,
                 RegisteredEventListeners registeredEventListeners);
    public  Cache(String name,
                 int maxElementsInMemory,
                 MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
                 boolean overflowToDisk,
                 String diskStorePath,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds,
                 RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader);
    public  Cache(String name,
                 int maxElementsInMemory,
                 MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
                 boolean overflowToDisk,
                 String diskStorePath,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds,
                 RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader,
                 int maxElementsOnDisk);
    public  Cache(String name,
                 int maxElementsInMemory,
                 MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
                 boolean overflowToDisk,
                 String diskStorePath,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds,
                 RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader,
                 int maxElementsOnDisk,
                 int diskSpoolBufferSizeMB);
    public  Cache(String name,
                 int maxElementsInMemory,
                 MemoryStoreEvictionPolicy memoryStoreEvictionPolicy,
                 boolean overflowToDisk,
                 String diskStorePath,
                 boolean eternal,
                 long timeToLiveSeconds,
                 long timeToIdleSeconds,
                 boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds,
                 RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader,
                 int maxElementsOnDisk,
                 int diskSpoolBufferSizeMB,
                 boolean clearOnFlush);
    public  Cache(String name, int maxElementsInMemory, MemoryStoreEvictionPolicy memoryStoreEvictionPolicy, boolean overflowToDisk,
                 String diskStorePath, boolean eternal, long timeToLiveSeconds, long timeToIdleSeconds, boolean diskPersistent,
                 long diskExpiryThreadIntervalSeconds, RegisteredEventListeners registeredEventListeners,
                 BootstrapCacheLoader bootstrapCacheLoader, int maxElementsOnDisk, int diskSpoolBufferSizeMB, boolean clearOnFlush,
                 boolean isTerracottaClustered, String terracottaValueMode, boolean terracottaCoherentReads);

}