Java tutorial
/* * 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.util.queue; import org.mule.api.MuleRuntimeException; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Control information for queues. * <p/> * Provides information about the current write and read file that were used * at the moment of the shutdown. */ public class QueueControlDataFile { private final Log logger = LogFactory.getLog(this.getClass()); public static final int INTEGER_SIZE_IN_BYTES = Integer.SIZE / 8; private final QueueFileProvider queueFileProvider; private File currentReadFilePath; private File currentWriteFilePath; /** * Creates a QueueControlDataFile for storing / retrieving information * * @param queueFileProvider file provider to use to store control data * @param firstFile first queue file. Used for write and read in case there is no control data yet. * @param secondFile second queue file. */ public QueueControlDataFile(QueueFileProvider queueFileProvider, File firstFile, File secondFile) { this.queueFileProvider = queueFileProvider; if (queueFileProvider.isNewFile()) { this.currentWriteFilePath = firstFile; this.currentReadFilePath = firstFile; writeControlData(currentWriteFilePath, currentReadFilePath); } else { try { this.currentWriteFilePath = getStoredFile(); this.currentReadFilePath = getStoredFile(); } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("failure reading queue control data from file " + queueFileProvider.getFile().getAbsolutePath(), e); } //perhaps mule crashed while this file was written. File lastUpdatedFile = firstFile.lastModified() > secondFile.lastModified() ? firstFile : secondFile; this.currentWriteFilePath = lastUpdatedFile; this.currentReadFilePath = firstFile == lastUpdatedFile ? secondFile : firstFile; } } } /** * Updates the control data * * @param writeFile file that is used for writing * @param readFile file that is used for reading */ public void writeControlData(File writeFile, File readFile) { try { queueFileProvider.getRandomAccessFile().seek(0); final String writeFilePath = writeFile.getAbsolutePath(); final String readFilePath = readFile.getAbsolutePath(); final ByteBuffer controlDataBuffer = ByteBuffer.allocate( writeFilePath.length() + INTEGER_SIZE_IN_BYTES + readFilePath.length() + INTEGER_SIZE_IN_BYTES); controlDataBuffer.putInt(writeFilePath.length()); controlDataBuffer.put(writeFilePath.getBytes()); controlDataBuffer.putInt(readFilePath.length()); controlDataBuffer.put(readFilePath.getBytes()); queueFileProvider.getRandomAccessFile().write(controlDataBuffer.array()); this.currentReadFilePath = readFile; this.currentWriteFilePath = writeFile; } catch (IOException e) { throw new MuleRuntimeException(e); } } /** * @return path of the current file that is used for reading */ public File getCurrentReadFile() { return currentReadFilePath; } /** * @return path of the current file that is used for writing */ public File getCurrentWriteFile() { return currentWriteFilePath; } private File getStoredFile() throws IOException { return new File(readStringFromFile()); } private String readStringFromFile() throws IOException { final int stringSize = queueFileProvider.getRandomAccessFile().readInt(); final byte[] stringAsBytes = new byte[stringSize]; queueFileProvider.getRandomAccessFile().read(stringAsBytes); return new String(stringAsBytes); } /** * useful for testing * * @return the QueueFileProvider used for storing the content */ QueueFileProvider getQueueFileProvider() { return queueFileProvider; } public void close() { try { queueFileProvider.close(); } catch (IOException e) { logger.warn("failure closing queue data control file: " + e.getMessage()); if (logger.isDebugEnabled()) { logger.debug(e); } } } /** * Deletes the underlying file. This method must only be invoked * after {@link #close()} has been executed on {@code this} * instance */ public void delete() { queueFileProvider.delete(); } }