/**
*
* Copyright 2004 Protique 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 org.codehaus.activemq.store.jdbm;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.Map;
import java.util.Properties;
import javax.jms.JMSException;
import jdbm.RecordManager;
import jdbm.RecordManagerFactory;
import jdbm.btree.BTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.AlreadyClosedException;
import org.codehaus.activemq.service.impl.PersistenceAdapterSupport;
import org.codehaus.activemq.store.MessageStore;
import org.codehaus.activemq.store.TopicMessageStore;
import org.codehaus.activemq.store.TransactionStore;
import org.codehaus.activemq.store.vm.VMTransactionStore;
import org.codehaus.activemq.util.DefaultComparator;
import org.codehaus.activemq.util.JMSExceptionHelper;
/**
* A {@link org.codehaus.activemq.store.PersistenceAdapter} implementation for
* <a href="http://jdbm.sf.net/">JDBM</a>
*
* @version $Revision: 1.2 $
*/
public class JdbmPersistenceAdapter extends PersistenceAdapterSupport {
private static final Log log = LogFactory.getLog(JdbmPersistenceAdapter.class);
private RecordManager manager;
private File directory = new File("ActiveMQ");
private Properties properties;
VMTransactionStore transactionStore = new VMTransactionStore();
/**
* Factory method to create an instance using the defaults
*
* @param directory the directory in which to store the persistent files
* @return
* @throws JMSException
*/
public static JdbmPersistenceAdapter newInstance(File directory) throws JMSException {
return new JdbmPersistenceAdapter(directory);
}
public JdbmPersistenceAdapter() {
}
public JdbmPersistenceAdapter(File directory) {
this.directory = directory;
}
public JdbmPersistenceAdapter(RecordManager manager) {
this.manager = manager;
}
public Map getInitialDestinations() {
return null; /** TODO */
}
public MessageStore createQueueMessageStore(String destinationName) throws JMSException {
try {
BTree messageDb = createDatabase("Queue_" + destinationName);
BTree sequenceDb = createDatabase("Sequence_Queue_" + destinationName);
JdbmMessageStore messageStore = new JdbmMessageStore(messageDb, sequenceDb);
return transactionStore.proxy(messageStore);
}
catch (IOException e) {
throw JMSExceptionHelper.newJMSException("Failed to create a QueueMessageContainer for destination: " + destinationName + ". Reason: " + e, e);
}
}
public TopicMessageStore createTopicMessageStore(String destinationName) throws JMSException {
try {
BTree messageDb = createDatabase("Topic_" + destinationName);
BTree sequenceDb = createDatabase("Sequence_Topic_" + destinationName);
BTree consumerAckDb = createDatabase("Consumer_Acks_Topic_" + destinationName);
BTree subscriberDb = createDatabase("Subscriber_" + destinationName);
BTree messageCountDb = createDatabase("MessageCount_Topic_" + destinationName);
JdbmTopicMessageStore messageStore = new JdbmTopicMessageStore(messageDb, sequenceDb, consumerAckDb, subscriberDb, messageCountDb);
return transactionStore.proxy(messageStore);
}
catch (IOException e) {
throw JMSExceptionHelper.newJMSException("Failed to create a TopicMessageContainer for destination: " + destinationName + ". Reason: " + e, e);
}
}
public TransactionStore createTransactionStore() throws JMSException {
return transactionStore;
}
public void beginTransaction() {
}
public void commitTransaction() throws JMSException {
try {
manager.commit();
}
catch (IOException e) {
throw JMSExceptionHelper.newJMSException("Could not commit transaction. Reason: " + e, e);
}
}
public void rollbackTransaction() {
try {
manager.rollback();
}
catch (IOException e) {
log.error("Could not rollback transaction. Reason: " + e, e);
}
}
public void start() throws JMSException {
if (manager == null) {
directory.mkdirs();
log.info("Creating JDBM based message store in directory: " + directory.getAbsolutePath());
try {
String name = directory.getAbsolutePath() + "/Store";
if (properties != null) {
manager = RecordManagerFactory.createRecordManager(name, properties);
}
else {
manager = RecordManagerFactory.createRecordManager(name);
}
}
catch (IOException e) {
throw JMSExceptionHelper.newJMSException("Failed to create JDBM persistent store at directory: "
+ directory + ". Reason: " + e, e);
}
}
}
public synchronized void stop() throws JMSException {
if (manager != null) {
try {
manager.close();
}
catch (IOException e) {
throw JMSExceptionHelper.newJMSException("Failed to close PersistenceAdapter. Reason: " + e, e);
}
finally {
manager = null;
}
}
}
// Properties
//-------------------------------------------------------------------------
public RecordManager getManager() {
return manager;
}
public void setManager(RecordManager manager) {
this.manager = manager;
}
public File getDirectory() {
return directory;
}
public void setDirectory(File directory) {
this.directory = directory;
}
// Implementation methods
//-------------------------------------------------------------------------
public synchronized BTree createDatabase(String name) throws IOException, AlreadyClosedException {
if (manager == null) {
throw new AlreadyClosedException("JDBM PersistenceAdapter");
}
// try to reload an existing B+Tree
long recid = manager.getNamedObject(name);
BTree tree = null;
if (recid != 0) {
tree = BTree.load(manager, recid);
}
else {
Comparator comparator = new DefaultComparator();
//Comparator comparator = new ObjectBAComparator(new DefaultComparator());
tree = BTree.createInstance(manager, comparator);
manager.setNamedObject(name, tree.getRecid());
}
return tree;
}
}