/*
* 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.exoplatform.social.core.storage.cache;
import org.exoplatform.services.cache.ExoCache;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.profile.ProfileFilter;
import org.exoplatform.social.core.storage.IdentityStorageException;
import org.exoplatform.social.core.storage.cache.model.data.ListIdentitiesData;
import org.exoplatform.social.core.storage.cache.model.key.ListIdentitiesKey;
import org.exoplatform.social.core.storage.impl.IdentityStorageImpl;
import org.exoplatform.social.core.storage.api.IdentityStorage;
import org.exoplatform.social.core.storage.cache.loader.ServiceContext;
import org.exoplatform.social.core.storage.cache.model.data.IdentityData;
import org.exoplatform.social.core.storage.cache.model.data.IntegerData;
import org.exoplatform.social.core.storage.cache.model.data.ProfileData;
import org.exoplatform.social.core.storage.cache.model.key.IdentityCompositeKey;
import org.exoplatform.social.core.storage.cache.model.key.IdentityFilterKey;
import org.exoplatform.social.core.storage.cache.model.key.IdentityKey;
import java.util.ArrayList;
import java.util.List;
/**
* Cache support for IdentityStorage.
*
* @author <a href="mailto:alain.defrance@exoplatform.com">Alain Defrance</a>
* @version $Revision$
*/
public class CachedIdentityStorage implements IdentityStorage {
private final ExoCache<IdentityKey, IdentityData> exoIdentityCache;
private final ExoCache<IdentityCompositeKey, IdentityKey> exoIdentityIndexCache;
private final ExoCache<IdentityKey, ProfileData> exoProfileCache;
private final ExoCache<IdentityFilterKey, IntegerData> exoIdentitiesCountCache;
private final ExoCache<ListIdentitiesKey, ListIdentitiesData> exoIdentitiesCache;
private final FutureExoCache<IdentityKey, IdentityData, ServiceContext<IdentityData>> identityCache;
private final FutureExoCache<IdentityCompositeKey, IdentityKey, ServiceContext<IdentityKey>> identityIndexCache;
private final FutureExoCache<IdentityKey, ProfileData, ServiceContext<ProfileData>> profileCache;
private final FutureExoCache<IdentityFilterKey, IntegerData, ServiceContext<IntegerData>> identitiesCountCache;
private final FutureExoCache<ListIdentitiesKey, ListIdentitiesData, ServiceContext<ListIdentitiesData>> identitiesCache;
private final IdentityStorageImpl storage;
/**
* Build the identity list from the caches Ids.
*
* @param data ids
* @return identities
*/
private List<Identity> buildIdentities(ListIdentitiesData data) {
List<Identity> identities = new ArrayList<Identity>();
for (IdentityKey k : data.getIds()) {
Identity gotIdentity = findIdentityById(k.getId());
gotIdentity.setProfile(loadProfile(gotIdentity.getProfile()));
identities.add(gotIdentity);
}
return identities;
}
/**
* Build the ids from the identitiy list.
*
* @param identities identities
* @return ids
*/
private ListIdentitiesData buildIds(List<Identity> identities) {
List<IdentityKey> data = new ArrayList<IdentityKey>();
for (Identity i : identities) {
IdentityKey k = new IdentityKey(i);
exoIdentityCache.put(k, new IdentityData(i));
exoProfileCache.put(k, new ProfileData(i.getProfile()));
data.add(new IdentityKey(i));
}
return new ListIdentitiesData(data);
}
public CachedIdentityStorage(final IdentityStorageImpl storage, final SocialStorageCacheService cacheService) {
//
this.storage = storage;
this.storage.setStorage(this);
//
this.exoIdentityCache = cacheService.getIdentityCache();
this.exoIdentityIndexCache = cacheService.getIdentityIndexCache();
this.exoProfileCache = cacheService.getProfileCache();
this.exoIdentitiesCountCache = cacheService.getCountIdentitiesCache();
this.exoIdentitiesCache = cacheService.getIdentitiesCache();
//
this.identityCache = CacheType.IDENTITY.createFutureCache(exoIdentityCache);
this.identityIndexCache = CacheType.IDENTITY_INDEX.createFutureCache(exoIdentityIndexCache);
this.profileCache = CacheType.PROFILE.createFutureCache(exoProfileCache);
this.identitiesCountCache = CacheType.IDENTITIES_COUNT.createFutureCache(exoIdentitiesCountCache);
this.identitiesCache = CacheType.IDENTITIES.createFutureCache(exoIdentitiesCache);
}
/**
* {@inheritDoc}
*/
public void saveIdentity(final Identity identity) throws IdentityStorageException {
//
storage.saveIdentity(identity);
//
IdentityKey key = new IdentityKey(new Identity(identity.getId()));
exoIdentityCache.put(key, new IdentityData(identity));
exoIdentitiesCountCache.clearCache();
exoIdentitiesCache.clearCache();
}
/**
* {@inheritDoc}
*/
public Identity updateIdentity(final Identity identity) throws IdentityStorageException {
//
IdentityKey key = new IdentityKey(new Identity(identity.getId()));
exoIdentityCache.remove(key);
exoIdentitiesCountCache.clearCache();
exoIdentitiesCache.clearCache();
//
return storage.updateIdentity(identity);
}
/**
* {@inheritDoc}
*/
public Identity findIdentityById(final String nodeId) throws IdentityStorageException {
IdentityKey key = new IdentityKey(new Identity(nodeId));
Identity i = identityCache.get(
new ServiceContext<IdentityData>() {
public IdentityData execute() {
return new IdentityData(storage.findIdentityById(nodeId));
}
},
key)
.build();
//
if (i != null) {
i.setProfile(loadProfile(i.getProfile()));
}
//
return i;
}
/**
* {@inheritDoc}
*/
public void deleteIdentity(final Identity identity) throws IdentityStorageException {
//
storage.deleteIdentity(identity);
//
IdentityKey key = new IdentityKey(new Identity(identity.getId()));
IdentityData data = exoIdentityCache.remove(key);
if (data != null) {
exoIdentityIndexCache.remove(new IdentityCompositeKey(data.getProviderId(), data.getRemoteId()));
}
exoProfileCache.remove(key);
exoIdentitiesCountCache.clearCache();
exoIdentitiesCache.clearCache();
}
/**
* {@inheritDoc}
*/
public Profile loadProfile(final Profile profile) throws IdentityStorageException {
IdentityKey key = new IdentityKey(new Identity(profile.getIdentity().getId()));
return profileCache.get(
new ServiceContext<ProfileData>() {
public ProfileData execute() {
return new ProfileData(storage.loadProfile(profile));
}
},
key)
.build();
}
/**
* {@inheritDoc}
*/
public Identity findIdentity(final String providerId, final String remoteId) throws IdentityStorageException {
//
IdentityCompositeKey key = new IdentityCompositeKey(providerId, remoteId);
//
IdentityKey k = identityIndexCache.get(
new ServiceContext<IdentityKey>() {
public IdentityKey execute() {
Identity i = storage.findIdentity(providerId, remoteId);
if (i == null) return null;
IdentityKey key = new IdentityKey(i);
exoIdentityCache.put(key, new IdentityData(i));
return key;
}
},
key);
//
if (k != null) {
return findIdentityById(k.getId());
}
else {
return null;
}
}
/**
* {@inheritDoc}
*/
public void saveProfile(final Profile profile) throws IdentityStorageException {
//
storage.saveProfile(profile);
//
IdentityKey key = new IdentityKey(new Identity(profile.getIdentity().getId()));
exoProfileCache.remove(key);
}
/**
* {@inheritDoc}
*/
public void updateProfile(final Profile profile) throws IdentityStorageException {
//
storage.updateProfile(profile);
//
IdentityKey key = new IdentityKey(new Identity(profile.getIdentity().getId()));
exoProfileCache.remove(key);
}
/**
* {@inheritDoc}
*/
public int getIdentitiesCount(final String providerId) throws IdentityStorageException {
return storage.getIdentitiesCount(providerId);
}
/**
* {@inheritDoc}
*/
public List<Identity> getIdentitiesByProfileFilter(final String providerId, final ProfileFilter profileFilter,
final long offset, final long limit, final boolean forceLoadOrReloadProfile) throws IdentityStorageException {
//
IdentityFilterKey key = new IdentityFilterKey(providerId, profileFilter);
ListIdentitiesKey listKey = new ListIdentitiesKey(key, offset, limit);
//
ListIdentitiesData keys = identitiesCache.get(
new ServiceContext<ListIdentitiesData>() {
public ListIdentitiesData execute() {
List<Identity> got = storage.getIdentitiesByProfileFilter(
providerId, profileFilter, offset, limit, forceLoadOrReloadProfile);
return buildIds(got);
}
},
listKey);
//
return buildIdentities(keys);
}
/**
* {@inheritDoc}
*/
public int getIdentitiesByProfileFilterCount(final String providerId, final ProfileFilter profileFilter)
throws IdentityStorageException {
//
IdentityFilterKey key = new IdentityFilterKey(providerId, profileFilter);
//
return identitiesCountCache.get(
new ServiceContext<IntegerData>() {
public IntegerData execute() {
return new IntegerData(storage.getIdentitiesByProfileFilterCount(providerId, profileFilter));
}
},
key)
.build();
}
/**
* {@inheritDoc}
*/
public int getIdentitiesByFirstCharacterOfNameCount(final String providerId, final ProfileFilter profileFilter)
throws IdentityStorageException {
//
IdentityFilterKey key = new IdentityFilterKey(providerId, profileFilter);
//
return identitiesCountCache.get(
new ServiceContext<IntegerData>() {
public IntegerData execute() {
return new IntegerData(storage.getIdentitiesByFirstCharacterOfNameCount(providerId, profileFilter));
}
},
key)
.build();
}
/**
* {@inheritDoc}
*/
public List<Identity> getIdentitiesByFirstCharacterOfName(final String providerId, final ProfileFilter profileFilter,
final long offset, final long limit, final boolean forceLoadOrReloadProfile) throws IdentityStorageException {
//
IdentityFilterKey key = new IdentityFilterKey(providerId, profileFilter);
ListIdentitiesKey listKey = new ListIdentitiesKey(key, offset, limit);
//
ListIdentitiesData keys = identitiesCache.get(
new ServiceContext<ListIdentitiesData>() {
public ListIdentitiesData execute() {
List<Identity> got = storage.getIdentitiesByFirstCharacterOfName(
providerId, profileFilter, offset, limit, forceLoadOrReloadProfile);
return buildIds(got);
}
},
listKey);
//
return buildIdentities(keys);
}
/**
* {@inheritDoc}
*/
public String getType(final String nodetype, final String property) {
return storage.getType(nodetype, property);
}
/**
* {@inheritDoc}
*/
public void addOrModifyProfileProperties(final Profile profile) throws IdentityStorageException {
storage.addOrModifyProfileProperties(profile);
}
}