/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.activemq.store.journal;
import java.io.File;
import java.io.IOException;
import org.apache.activeio.journal.Journal;
import org.apache.activeio.journal.active.JournalImpl;
import org.apache.activeio.journal.active.JournalLockedException;
import org.apache.activemq.broker.Locker;
import org.apache.activemq.store.PersistenceAdapter;
import org.apache.activemq.store.PersistenceAdapterFactory;
import org.apache.activemq.store.jdbc.DataSourceServiceSupport;
import org.apache.activemq.store.jdbc.JDBCAdapter;
import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter;
import org.apache.activemq.store.jdbc.Statements;
import org.apache.activemq.thread.TaskRunnerFactory;
import org.apache.activemq.util.ServiceStopper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Factory class that can create PersistenceAdapter objects.
*
* @org.apache.xbean.XBean
*
*/
public class JournalPersistenceAdapterFactory extends DataSourceServiceSupport implements PersistenceAdapterFactory {
private static final int JOURNAL_LOCKED_WAIT_DELAY = 10 * 1000;
private static final Logger LOG = LoggerFactory.getLogger(JournalPersistenceAdapterFactory.class);
private long checkpointInterval = 1000 * 60 * 5;
private int journalLogFileSize = 1024 * 1024 * 20;
private int journalLogFiles = 2;
private TaskRunnerFactory taskRunnerFactory;
private Journal journal;
private boolean useJournal = true;
private boolean useQuickJournal;
private File journalArchiveDirectory;
private boolean failIfJournalIsLocked;
private int journalThreadPriority = Thread.MAX_PRIORITY;
private JDBCPersistenceAdapter jdbcPersistenceAdapter = new JDBCPersistenceAdapter();
private boolean useDedicatedTaskRunner;
public PersistenceAdapter createPersistenceAdapter() throws IOException {
jdbcPersistenceAdapter.setDataSource(getDataSource());
if (!useJournal) {
return jdbcPersistenceAdapter;
}
JournalPersistenceAdapter result = new JournalPersistenceAdapter(getJournal(), jdbcPersistenceAdapter, getTaskRunnerFactory());
result.setDirectory(getDataDirectoryFile());
result.setCheckpointInterval(getCheckpointInterval());
return result;
}
public int getJournalLogFiles() {
return journalLogFiles;
}
/**
* Sets the number of journal log files to use
*/
public void setJournalLogFiles(int journalLogFiles) {
this.journalLogFiles = journalLogFiles;
}
public int getJournalLogFileSize() {
return journalLogFileSize;
}
/**
* Sets the size of the journal log files
* When set using Xbean, values of the form "20 Mb", "1024kb", and "1g" can be used
* @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryIntPropertyEditor"
*/
public void setJournalLogFileSize(int journalLogFileSize) {
this.journalLogFileSize = journalLogFileSize;
}
public JDBCPersistenceAdapter getJdbcAdapter() {
return jdbcPersistenceAdapter;
}
public void setJdbcAdapter(JDBCPersistenceAdapter jdbcAdapter) {
this.jdbcPersistenceAdapter = jdbcAdapter;
}
public boolean isUseJournal() {
return useJournal;
}
public long getCheckpointInterval() {
return checkpointInterval;
}
public void setCheckpointInterval(long checkpointInterval) {
this.checkpointInterval = checkpointInterval;
}
/**
* Enables or disables the use of the journal. The default is to use the
* journal
*
* @param useJournal
*/
public void setUseJournal(boolean useJournal) {
this.useJournal = useJournal;
}
public boolean isUseDedicatedTaskRunner() {
return useDedicatedTaskRunner;
}
public void setUseDedicatedTaskRunner(boolean useDedicatedTaskRunner) {
this.useDedicatedTaskRunner = useDedicatedTaskRunner;
}
public TaskRunnerFactory getTaskRunnerFactory() {
if (taskRunnerFactory == null) {
taskRunnerFactory = new TaskRunnerFactory("Persistence Adaptor Task", journalThreadPriority,
true, 1000, isUseDedicatedTaskRunner());
}
return taskRunnerFactory;
}
public void setTaskRunnerFactory(TaskRunnerFactory taskRunnerFactory) {
this.taskRunnerFactory = taskRunnerFactory;
}
public Journal getJournal() throws IOException {
if (journal == null) {
createJournal();
}
return journal;
}
public void setJournal(Journal journal) {
this.journal = journal;
}
public File getJournalArchiveDirectory() {
if (journalArchiveDirectory == null && useQuickJournal) {
journalArchiveDirectory = new File(getDataDirectoryFile(), "journal");
}
return journalArchiveDirectory;
}
public void setJournalArchiveDirectory(File journalArchiveDirectory) {
this.journalArchiveDirectory = journalArchiveDirectory;
}
public boolean isUseQuickJournal() {
return useQuickJournal;
}
/**
* Enables or disables the use of quick journal, which keeps messages in the
* journal and just stores a reference to the messages in JDBC. Defaults to
* false so that messages actually reside long term in the JDBC database.
*/
public void setUseQuickJournal(boolean useQuickJournal) {
this.useQuickJournal = useQuickJournal;
}
public JDBCAdapter getAdapter() throws IOException {
return jdbcPersistenceAdapter.getAdapter();
}
public void setAdapter(JDBCAdapter adapter) {
jdbcPersistenceAdapter.setAdapter(adapter);
}
public Statements getStatements() {
return jdbcPersistenceAdapter.getStatements();
}
public void setStatements(Statements statements) {
jdbcPersistenceAdapter.setStatements(statements);
}
/**
* Sets whether or not an exclusive database lock should be used to enable
* JDBC Master/Slave. Enabled by default.
*/
public void setUseDatabaseLock(boolean useDatabaseLock) {
jdbcPersistenceAdapter.setUseLock(useDatabaseLock);
}
public boolean isCreateTablesOnStartup() {
return jdbcPersistenceAdapter.isCreateTablesOnStartup();
}
/**
* Sets whether or not tables are created on startup
*/
public void setCreateTablesOnStartup(boolean createTablesOnStartup) {
jdbcPersistenceAdapter.setCreateTablesOnStartup(createTablesOnStartup);
}
public int getJournalThreadPriority() {
return journalThreadPriority;
}
/**
* Sets the thread priority of the journal thread
*/
public void setJournalThreadPriority(int journalThreadPriority) {
this.journalThreadPriority = journalThreadPriority;
}
/**
* @throws IOException
*/
protected void createJournal() throws IOException {
File journalDir = new File(getDataDirectoryFile(), "journal").getCanonicalFile();
if (failIfJournalIsLocked) {
journal = new JournalImpl(journalDir, journalLogFiles, journalLogFileSize,
getJournalArchiveDirectory());
} else {
while (true) {
try {
journal = new JournalImpl(journalDir, journalLogFiles, journalLogFileSize,
getJournalArchiveDirectory());
break;
} catch (JournalLockedException e) {
LOG.info("Journal is locked... waiting " + (JOURNAL_LOCKED_WAIT_DELAY / 1000)
+ " seconds for the journal to be unlocked.");
try {
Thread.sleep(JOURNAL_LOCKED_WAIT_DELAY);
} catch (InterruptedException e1) {
}
}
}
}
}
@Override
public Locker createDefaultLocker() throws IOException {
return null;
}
@Override
public void init() throws Exception {
}
@Override
protected void doStop(ServiceStopper stopper) throws Exception {}
@Override
protected void doStart() throws Exception {}
}