/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.cache; import java.util.List; import java.util.Map; import net.sf.ehcache.CacheManager; import org.fudgemsg.FudgeContext; import org.fudgemsg.FudgeMsg; import org.fudgemsg.FudgeMsgEnvelope; import org.fudgemsg.mapping.FudgeDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.engine.cache.msg.CacheMessage; import com.opengamma.engine.cache.msg.CacheMessageVisitor; import com.opengamma.engine.cache.msg.FindMessage; import com.opengamma.engine.cache.msg.ReleaseCacheMessage; import com.opengamma.transport.FudgeMessageReceiver; /** * Caching client for {@link ViewComputationCacheServer}. */ public class RemoteViewComputationCacheSource extends DefaultViewComputationCacheSource implements FudgeMessageReceiver { private static final Logger s_logger = LoggerFactory.getLogger(RemoteViewComputationCacheSource.class); public RemoteViewComputationCacheSource(final RemoteCacheClient client, final FudgeMessageStoreFactory privateDataStoreFactory, final CacheManager cacheManager) { this(client, privateDataStoreFactory, client.getFudgeContext(), cacheManager); } /** * @param client the connection to a {@link ViewComputationCacheServer} * @param privateDataStoreFactory the private data store - the shared data store will be the remote one * @param fudgeContext the Fudge context the {@link DefaultViewComputationCache} will use for object encoding. This may be the same as the * one attached to the client's transport or different. * @param cacheManager the EH cache manager to use for the remote binary data store */ public RemoteViewComputationCacheSource(final RemoteCacheClient client, final FudgeMessageStoreFactory privateDataStoreFactory, final FudgeContext fudgeContext, final CacheManager cacheManager) { super(createIdentifierMap(client), fudgeContext, privateDataStoreFactory, createFudgeMessageStoreFactory(client, cacheManager)); client.setAsynchronousMessageReceiver(this); } private static IdentifierMap createIdentifierMap(final RemoteCacheClient client) { return new CachingIdentifierMap(new RemoteIdentifierMap(client)); } private static FudgeMessageStoreFactory createFudgeMessageStoreFactory(final RemoteCacheClient client, final CacheManager cacheManager) { final RemoteFudgeMessageStoreFactory remote = new RemoteFudgeMessageStoreFactory(client); return new CachingFudgeMessageStoreFactory(remote, cacheManager); } private final CacheMessageVisitor _messageReceiver = new CacheMessageVisitor() { @Override protected CacheMessage visitReleaseCacheMessage(final ReleaseCacheMessage message) { s_logger.debug("Releasing caches for cycle {}", message.getViewCycleId()); // [ENG-256] make sure we don't cause a cascade of messages if e.g. release called on a client, must cause release on server, which must send release to other clients but these must not generate // further messages releaseCaches(message.getViewCycleId()); return null; } @Override protected CacheMessage visitFindMessage(final FindMessage message) { final DefaultViewComputationCache cache = findCache(message.getViewCycleId(), message.getCalculationConfigurationName()); if (cache != null) { final List<Long> identifiers = message.getIdentifier(); s_logger.debug("Searching for {} identifiers to send to shared cache", identifiers.size()); if (identifiers.size() == 1) { final long identifier = identifiers.get(0); final FudgeMsg data = cache.getPrivateDataStore().get(identifier); if (data != null) { s_logger.debug("Found identifier {} in private cache", identifier); cache.getSharedDataStore().put(identifier, data); } } else { final Map<Long, FudgeMsg> data = cache.getPrivateDataStore().get(identifiers); if (data.size() == 1) { s_logger.debug("Found 1 of {} identifiers in private cache", identifiers.size()); final Map.Entry<Long, FudgeMsg> entry = data.entrySet().iterator().next(); cache.getSharedDataStore().put(entry.getKey(), entry.getValue()); } else if (data.size() > 1) { s_logger.debug("Found {} of {} identifiers in private cache", data.size(), identifiers.size()); cache.getSharedDataStore().put(data); } } } return null; } @Override protected <T extends CacheMessage> T visitUnexpectedMessage(final CacheMessage message) { s_logger.warn("Unexpected message {}", message); return null; } }; // [ENG-256] Override, or register callback handler for releaseCaches so that if it is called by user code we propogate the message to the server and other clients, noting the warning about cascade // above @Override public void messageReceived(final FudgeContext fudgeContext, final FudgeMsgEnvelope msgEnvelope) { final FudgeDeserializer deserializer = new FudgeDeserializer(fudgeContext); final CacheMessage message = deserializer.fudgeMsgToObject(CacheMessage.class, msgEnvelope.getMessage()); message.accept(_messageReceiver); } }