/*
* Copyright (C) 2003-2011 eXo Platform SAS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.etk.storage.core.impl;
import java.util.ArrayList;
import java.util.List;
import org.etk.kernel.cache.ExoCache;
import org.etk.service.foo.FooFilter;
import org.etk.service.foo.model.Bar;
import org.etk.service.foo.model.Foo;
import org.etk.storage.api.FooStorage;
import org.etk.storage.core.impl.jcr.FooStorageImpl;
import org.etk.storage.plugins.cache.CacheType;
import org.etk.storage.plugins.cache.FactoryStorageCacheService;
import org.etk.storage.plugins.cache.FutureETKCache;
import org.etk.storage.plugins.cache.loader.ServiceContext;
import org.etk.storage.plugins.cache.model.data.BarData;
import org.etk.storage.plugins.cache.model.data.FooData;
import org.etk.storage.plugins.cache.model.data.IntegerData;
import org.etk.storage.plugins.cache.model.data.ListFoosData;
import org.etk.storage.plugins.cache.model.key.FooFilterKey;
import org.etk.storage.plugins.cache.model.key.FooKey;
import org.etk.storage.plugins.cache.model.key.ListFoosKey;
/**
* Created by The eXo Platform SAS
* Author : eXoPlatform
* exo@exoplatform.com
* Jul 22, 2011
*/
public class CachedFooStorage implements FooStorage {
private final ExoCache<FooKey, FooData> etkFooCache;
private final ExoCache<FooKey, BarData> etkBarCache;
private final ExoCache<FooFilterKey, IntegerData> etkFoosCountCache;
private final ExoCache<ListFoosKey, ListFoosData> etkFoosCache;
private final FutureETKCache<FooKey, FooData, ServiceContext<FooData>> fooCache;
private final FutureETKCache<FooKey, BarData, ServiceContext<BarData>> barCache;
private final FutureETKCache<FooFilterKey, IntegerData, ServiceContext<IntegerData>> foosCountCache;
private final FutureETKCache<ListFoosKey, ListFoosData, ServiceContext<ListFoosData>> foosCache;
private final FooStorageImpl storage;
/**
* Build the Foo list from the caches Ids.
*
* @param data ids
* @return foos
*/
private List<Foo> buildFoos(ListFoosData data) {
List<Foo> foos = new ArrayList<Foo>();
for (FooKey k : data.getIds()) {
Foo got = findById(k.getId());
foos.add(got);
}
return foos;
}
/**
* Build the list of FooKey provides ListFoosData.
* @param foos
* @return
*/
private ListFoosData buildIds(List<Foo> foos) {
List<FooKey> fooKeys = new ArrayList<FooKey>();
for (Foo foo : foos) {
FooKey key = new FooKey(foo);
this.etkFooCache.put(key, new FooData(foo));
foo.setBar(loadBar(foo));
this.etkBarCache.put(key, new BarData(foo.getBar()));
fooKeys.add(new FooKey(foo));
}
return new ListFoosData(fooKeys);
}
/**
* Constructor to initialize the CachedFooStorage.
* @param storage
* @param cacheService
*/
public CachedFooStorage(final FooStorageImpl storage, final FactoryStorageCacheService cacheService) {
this.storage = storage;
this.storage.setStorage(this);
//Initializes the eXoCache which is managed by CacheService
this.etkFooCache = cacheService.getFooCache();
this.etkBarCache = cacheService.getBarCache();
this.etkFoosCountCache = cacheService.getFoosCountCache();
this.etkFoosCache = cacheService.getFoosCache();
//Initializes the EtkFutureCache which executes for caching ServiceContext
this.fooCache = CacheType.FOO.createFutureCache(etkFooCache);
this.foosCache = CacheType.FOOS.createFutureCache(etkFoosCache);
this.barCache = CacheType.BAR.createFutureCache(etkBarCache);
this.foosCountCache = CacheType.FOOS_COUNT.createFutureCache(etkFoosCountCache);
}
@Override
public List<Foo> getFooByFilter(final FooFilter fooFilter, final int offset, final int limit) {
FooFilterKey key = new FooFilterKey(fooFilter);
ListFoosKey listKey = new ListFoosKey(key, offset, limit);
ListFoosData keys = foosCache.get(new ServiceContext<ListFoosData>() {
@Override
public ListFoosData execute() {
List<Foo> got = storage.getFooByFilter(fooFilter, offset, limit);
return buildIds(got);
}
}, listKey);
return buildFoos(keys);
}
@Override
public int getFooByFilterCount(final FooFilter fooFilter) {
FooFilterKey key = new FooFilterKey(fooFilter);
return foosCountCache.get(new ServiceContext<IntegerData>() {
@Override
public IntegerData execute() {
return new IntegerData(storage.getFooByFilterCount(fooFilter));
}
}, key).build();
}
@Override
public Foo findById(final String id) {
FooKey key = new FooKey(new Foo(id));
Foo foo = fooCache.get(new ServiceContext<FooData>() {
public FooData execute() {
return new FooData(storage.findById(id));
}
}, key).build();
if (foo != null) {
foo.setBar(loadBar(foo));
}
return foo;
}
@Override
public Bar loadBar(final Foo foo) {
FooKey key = new FooKey(new Foo(foo.getId()));
return barCache.get(new ServiceContext<BarData>() {
@Override
public BarData execute() {
return new BarData(storage.loadBar(foo));
}
}, key).build();
}
@Override
public Foo saveFoo(final Foo foo) {
storage.saveFoo(foo);
FooKey key = new FooKey(foo);
etkFooCache.put(key, new FooData(foo));
etkFoosCountCache.clearCache();
return foo;
}
@Override
public void deleteFoo(final Foo existingFoo) {
storage.deleteFoo(existingFoo);
FooKey key = new FooKey(existingFoo);
etkFooCache.put(key, new FooData(existingFoo));
etkFoosCountCache.clearCache();
}
@Override
public Foo updateFoo(final Foo existingFoo) {
//
FooKey key = new FooKey(existingFoo);
etkFooCache.remove(key);
//
return storage.updateFoo(existingFoo);
}
}