/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.util.queue.objectstore;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.api.exception.MuleException;
import org.mule.runtime.core.api.context.MuleContextAware;
import org.mule.runtime.api.lifecycle.Disposable;
import org.mule.runtime.api.lifecycle.Stoppable;
import org.mule.runtime.core.api.store.ListableObjectStore;
import org.mule.runtime.api.store.ObjectStore;
import org.mule.runtime.api.store.ObjectStoreException;
import org.mule.runtime.core.api.store.QueueStore;
import org.mule.runtime.core.util.UUID;
import org.mule.runtime.core.util.queue.Queue;
import org.mule.runtime.core.util.queue.QueueManager;
import org.mule.runtime.core.util.queue.QueueSession;
import org.mule.runtime.core.util.queue.objectstore.xa.AbstractTransactionContext;
import org.mule.runtime.core.util.queue.objectstore.xa.AbstractXAResourceManager;
import org.mule.runtime.core.util.xa.ResourceManagerException;
import org.mule.runtime.core.util.xa.ResourceManagerSystemException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.transaction.xa.XAResource;
/**
* The Transactional Queue Manager is responsible for creating and Managing transactional Queues. Queues can also be persistent by
* setting a persistence strategy on the manager. Default straties are provided for Memory, Jounaling, Cache and File.
*
* @deprecated this class will be removed in Mule 4.0 in favor of the new queue implementation
*/
@Deprecated
public class TransactionalQueueManager extends AbstractXAResourceManager implements QueueManager, MuleContextAware {
private final Map<String, QueueInfo> queues = new HashMap<String, QueueInfo>();
private QueueConfiguration defaultQueueConfiguration;
private MuleContext muleContext;
private final Set<QueueStore> queueObjectStores = new HashSet<QueueStore>();
private final Set<ListableObjectStore> listableObjectStores = new HashSet<ListableObjectStore>();
private final ReadWriteLock queuesLock = new ReentrantReadWriteLock();
/**
* {@inheritDoc}
*
* @return an instance of {@link org.mule.runtime.core.util.queue.TransactionalQueueSession}
*/
@Override
public synchronized QueueSession getQueueSession() {
return new TransactionalQueueSession(this, this);
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void setDefaultQueueConfiguration(org.mule.runtime.core.util.queue.QueueConfiguration config) {
this.defaultQueueConfiguration = (QueueConfiguration) config;
addStore(((QueueConfiguration) config).objectStore);
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void setQueueConfiguration(String queueName, org.mule.runtime.core.util.queue.QueueConfiguration config) {
getQueue(queueName, (QueueConfiguration) config).setConfig((QueueConfiguration) config);
addStore(((QueueConfiguration) config).objectStore);
}
protected void disposeQueue(Queue queue) throws MuleException, InterruptedException {
if (queue == null) {
throw new IllegalArgumentException("Queue to be disposed cannot be null");
}
final String queueName = queue.getName();
Lock lock = this.queuesLock.writeLock();
lock.lock();
try {
if (!this.queues.containsKey(queueName)) {
throw new IllegalArgumentException(String.format("There's no queue for name %s", queueName));
}
this.queues.remove(queueName);
} finally {
lock.unlock();
}
queue.clear();
if (queue instanceof Stoppable) {
((Stoppable) queue).stop();
}
if (queue instanceof Disposable) {
((Disposable) queue).dispose();
}
}
protected QueueInfo getQueue(String name) {
return getQueue(name, defaultQueueConfiguration);
}
protected QueueInfo getQueue(String name, QueueConfiguration config) {
Lock lock = this.queuesLock.writeLock();
lock.lock();
try {
QueueInfo q = queues.get(name);
if (q == null) {
q = new QueueInfo(name, muleContext, config);
queues.put(name, q);
}
return q;
} finally {
lock.unlock();
}
}
public QueueInfo getQueueInfo(String name) {
Lock lock = this.queuesLock.readLock();
lock.lock();
try {
QueueInfo q = queues.get(name);
return q == null ? q : new QueueInfo(q);
} finally {
lock.unlock();
}
}
@Override
protected void doStart() throws ResourceManagerSystemException {
findAllListableObjectStores();
for (ListableObjectStore store : listableObjectStores) {
try {
store.open();
} catch (ObjectStoreException e) {
throw new ResourceManagerSystemException(e);
}
}
}
@Override
protected boolean shutdown(int mode, long timeoutMSecs) {
// Clear queues on shutdown to avoid duplicate entries on warm restarts
// (MULE-3678)
Lock lock = this.queuesLock.writeLock();
lock.lock();
try {
queues.clear();
} finally {
lock.unlock();
}
return super.shutdown(mode, timeoutMSecs);
}
@Override
protected void recover() throws ResourceManagerSystemException {
findAllQueueStores();
for (QueueStore store : queueObjectStores) {
if (!store.isPersistent()) {
continue;
}
try {
List<Serializable> keys = store.allKeys();
for (Serializable key : keys) {
// It may contain events that aren't part of a queue MULE-6007
if (key instanceof QueueKey) {
QueueKey queueKey = (QueueKey) key;
QueueInfo queue = getQueue(queueKey.queueName);
if (queue.isQueueTransient()) {
queue.putNow(queueKey.id);
}
}
}
} catch (Exception e) {
throw new ResourceManagerSystemException(e);
}
}
}
@Override
protected AbstractTransactionContext createTransactionContext(Object session) {
return new QueueTransactionContext(this);
}
@Override
protected void doBegin(AbstractTransactionContext context) {
// Nothing special to do
}
@Override
protected int doPrepare(AbstractTransactionContext context) {
return XAResource.XA_OK;
}
@Override
protected void doCommit(AbstractTransactionContext context) throws ResourceManagerException {
context.doCommit();
}
protected Serializable doStore(QueueInfo queue, Serializable object) throws ObjectStoreException {
ObjectStore<Serializable> store = queue.getStore();
String id = muleContext == null ? UUID.getUUID() : muleContext.getUniqueIdString();
Serializable key = new QueueKey(queue.getName(), id);
store.store(key, object);
return id;
}
protected void doClear(QueueInfo queue) throws ObjectStoreException, InterruptedException {
queue.clear();
}
protected void doRemove(QueueInfo queue, Serializable id) throws ObjectStoreException {
ObjectStore<Serializable> store = queue.getStore();
Serializable key = new QueueKey(queue.getName(), id);
store.remove(key);
}
protected Serializable doLoad(QueueInfo queue, Serializable id) throws ObjectStoreException {
ObjectStore<Serializable> store = queue.getStore();
Serializable key = new QueueKey(queue.getName(), id);
return store.retrieve(key);
}
@Override
protected void doRollback(AbstractTransactionContext context) throws ResourceManagerException {
context.doRollback();
}
protected void findAllListableObjectStores() {
if (muleContext != null) {
for (ListableObjectStore store : muleContext.getRegistry().lookupByType(ListableObjectStore.class).values()) {
addStore(store);
}
}
}
protected synchronized void findAllQueueStores() {
if (muleContext != null) {
for (QueueStore store : muleContext.getRegistry().lookupByType(QueueStore.class).values()) {
addStore(store);
}
}
}
@Override
public void setMuleContext(MuleContext context) {
this.muleContext = context;
}
public MuleContext getMuleContext() {
return muleContext;
}
private void addStore(ListableObjectStore<?> store) {
if (store instanceof QueueStore) {
queueObjectStores.add((QueueStore) store);
}
listableObjectStores.add(store);
}
}