
net.sf.ehcache.distribution.jms.JMSCacheLoader Maven / Gradle / Ivy
/**
* Copyright 2003-2008 Luck Consulting Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.ehcache.distribution.jms;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Status;
import static net.sf.ehcache.distribution.jms.JMSUtil.CACHE_MANAGER_UID;
import static net.sf.ehcache.distribution.jms.JMSUtil.localCacheManagerUid;
import net.sf.ehcache.loader.CacheLoader;
import net.sf.jsr107cache.CacheException;
import javax.jms.DeliveryMode;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TemporaryQueue;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Greg Luck
*/
public class JMSCacheLoader implements CacheLoader {
/**
* The highest JMS priority
*/
protected static final int HIGHEST_JMS_PRORITY = 9;
private static final Logger LOG = Logger.getLogger(JMSCacheLoader.class.getName());
/***/
protected QueueSender getQueueSender;
/***/
protected QueueSession getQueueSession;
/***/
protected int timeoutMillis;
/***/
protected Ehcache cache;
private AcknowledgementMode acknowledgementMode;
private Status status;
private QueueConnection getQueueConnection;
private String defaultLoaderArgument;
private Queue getQueue;
/**
* Constructor.
*
* @param cache
* @param defaultLoaderArgument
* @param getQueueConnection
* @param getQueue
* @param acknowledgementMode
* @param timeoutMillis
*/
public JMSCacheLoader(Ehcache cache, String defaultLoaderArgument,
QueueConnection getQueueConnection,
Queue getQueue,
AcknowledgementMode acknowledgementMode,
int timeoutMillis) {
this.cache = cache;
this.defaultLoaderArgument = defaultLoaderArgument;
this.getQueueConnection = getQueueConnection;
this.acknowledgementMode = acknowledgementMode;
this.getQueue = getQueue;
this.timeoutMillis = timeoutMillis;
status = Status.STATUS_UNINITIALISED;
}
/**
* loads an object. Application writers should implement this
* method to customize the loading of cache object. This method is called
* by the caching service when the requested object is not in the cache.
*
*
* @param key the key identifying the object being loaded
* @return The object that is to be stored in the cache.
* @throws net.sf.jsr107cache.CacheException
*
*/
public Object load(Object key) throws CacheException {
return load(key, null);
}
/**
* Load using both a key and an argument.
*
* JCache will call through to the load(key) method, rather than this method, where the argument is null.
*
* @param key the key to load the object for.
* @param argument can be anything that makes sense to the loader.
* The argument is converted to a String with toString()
* to use for the JMS StringProperty loaderArgument
* @return the Object loaded
* @throws net.sf.jsr107cache.CacheException
*
*/
public Object load(Object key, Object argument) throws CacheException {
Serializable keyAsSerializable = (Serializable) key;
Serializable effectiveLoaderArgument = effectiveLoaderArgument(argument);
JMSEventMessage jmsEventMessage = new JMSEventMessage(Action.GET,
keyAsSerializable, null, cache.getName(), effectiveLoaderArgument);
return loadFromJMS(jmsEventMessage);
}
/**
* A common loader which handles the JMS interactions.
*
* @param jmsEventMessage
* @return
* @throws CacheException
*/
protected Object loadFromJMS(JMSEventMessage jmsEventMessage) throws CacheException {
Object value;
MessageConsumer replyReceiver = null;
TemporaryQueue temporaryReplyQueue = null;
try {
ObjectMessage loadRequest = getQueueSession.createObjectMessage(jmsEventMessage);
temporaryReplyQueue = getQueueSession.createTemporaryQueue();
replyReceiver = getQueueSession.createConsumer(temporaryReplyQueue);
loadRequest.setJMSReplyTo(temporaryReplyQueue);
loadRequest.setIntProperty(CACHE_MANAGER_UID, localCacheManagerUid(cache));
getQueueSender.send(loadRequest, DeliveryMode.NON_PERSISTENT, HIGHEST_JMS_PRORITY, timeoutMillis);
//must send first before getting id
String initialMessageId = loadRequest.getJMSMessageID();
ObjectMessage reply = (ObjectMessage) replyReceiver.receive(timeoutMillis);
if (reply == null) {
return null;
}
String messageId = reply.getJMSCorrelationID();
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Initial ID: " + initialMessageId + ". Reply Correlation ID. " + messageId);
}
String responder = reply.getStringProperty("responder");
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Responder: " + responder);
}
assert initialMessageId.equals(messageId) : "The load request received an uncorrelated request. " +
"Request ID was " + messageId;
value = reply.getObject();
} catch (JMSException e) {
throw new CacheException("Problem loading: " + e.getMessage(), e);
} finally {
try {
replyReceiver.close();
temporaryReplyQueue.delete();
} catch (JMSException e) {
LOG.log(Level.SEVERE, "Problem closing JMS Resources: " + e.getMessage(), e);
}
}
return value;
}
/**
* loads multiple object. Application writers should implement this
* method to customize the loading of cache object. This method is called
* by the caching service when the requested object is not in the cache.
*
*
* @param keys a Collection of keys identifying the objects to be loaded
* @return A Map of objects that are to be stored in the cache.
* @throws net.sf.jsr107cache.CacheException
*
*/
public Map loadAll(Collection keys) throws CacheException {
return loadAll(keys, null);
}
/**
* Load using both a key and an argument.
*
* JCache will use the loadAll(key) method where the argument is null.
*
* @param keys a Collection
of keys to load objects for. Each key must be Serializable
.
* @param argument can be anything that makes sense to the loader. It must be Serializable
.
* @return a map of Objects keyed by the collection of keys passed in.
* @throws net.sf.jsr107cache.CacheException
*
*/
public Map loadAll(Collection keys, Object argument) throws CacheException {
Serializable effectiveLoaderArgument;
effectiveLoaderArgument = effectiveLoaderArgument(argument);
ArrayList requestList = new ArrayList();
for (Object key : keys) {
Serializable keyAsSerializable = (Serializable) key;
requestList.add(keyAsSerializable);
}
Map responseMap;
JMSEventMessage jmsEventMessage = new JMSEventMessage(Action.GET,
requestList, null, cache.getName(), effectiveLoaderArgument);
responseMap = (Map) loadFromJMS(jmsEventMessage);
return responseMap;
}
private Serializable effectiveLoaderArgument(Object argument) {
Serializable effectiveLoaderArgument;
if (argument == null) {
effectiveLoaderArgument = defaultLoaderArgument;
} else {
effectiveLoaderArgument = (Serializable) argument;
}
return effectiveLoaderArgument;
}
/**
* Gets the name of a CacheLoader
*
* @return the name of this CacheLoader
*/
public String getName() {
return "JMSCacheLoader with default loaderArgument: " + defaultLoaderArgument;
}
/**
* Creates a clone of this extension. This method will only be called by ehcache before a
* cache is initialized.
*
* Implementations should throw CloneNotSupportedException if they do not support clone
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheLoader clone(Ehcache cache) throws CloneNotSupportedException {
throw new CloneNotSupportedException("not supported");
}
/**
* Notifies providers to initialise themselves.
*
* This method is called during the Cache's initialise method after it has changed it's
* status to alive. Cache operations are legal in this method.
*
* @throws net.sf.ehcache.CacheException
*/
public void init() {
try {
getQueueConnection.setExceptionListener(new ExceptionListener() {
public void onException(JMSException e) {
LOG.log(Level.SEVERE, "Exception on getQueue Connection: " + e.getMessage(), e);
}
});
getQueueSession = getQueueConnection.createQueueSession(false, acknowledgementMode.toInt());
getQueueSender = getQueueSession.createSender(getQueue);
getQueueConnection.start();
status = Status.STATUS_ALIVE;
} catch (JMSException e) {
throw new net.sf.ehcache.CacheException("Exception while creating JMS connections: " + e.getMessage(), e);
}
}
/**
* Providers may be doing all sorts of exotic things and need to be able to clean up on
* dispose.
*
* Cache operations are illegal when this method is called. The cache itself is partly
* disposed when this method is called.
*
* @throws net.sf.ehcache.CacheException
*/
public void dispose() throws net.sf.ehcache.CacheException {
try {
getQueueConnection.stop();
getQueueSession.close();
getQueueSender.close();
getQueueConnection.close();
} catch (JMSException e) {
throw new net.sf.ehcache.CacheException("Problem stopping queue connection: " + e.getMessage(), e);
}
status = Status.STATUS_SHUTDOWN;
}
/**
* @return the status of the extension
*/
public Status getStatus() {
return status;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy