/**
* Copyright (C) 2007 Sly Technologies, Inc. This library is free software; you
* can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version. This
* library is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details. You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.slytechs.capture.file;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.jnetstream.capture.CapturePacket;
import org.jnetstream.capture.CaptureType;
import org.jnetstream.capture.FileCapture;
import org.jnetstream.capture.FilePacket;
import org.jnetstream.capture.PacketIndexer;
import org.jnetstream.capture.PacketIterator;
import org.jnetstream.capture.file.BlockRecord;
import org.jnetstream.capture.file.HeaderReader;
import org.jnetstream.capture.file.PacketCounterModel;
import org.jnetstream.capture.file.RawIndexer;
import org.jnetstream.capture.file.RawIterator;
import org.jnetstream.capture.file.Record;
import org.jnetstream.capture.file.RecordFilterTarget;
import org.jnetstream.capture.file.RecordIndexer;
import org.jnetstream.capture.file.RecordIterator;
import org.jnetstream.filter.Filter;
import org.jnetstream.packet.ProtocolFilterTarget;
import com.slytechs.capture.DefaultCaptureDevice;
import com.slytechs.capture.file.editor.FileEditor;
import com.slytechs.capture.file.indexer.PacketIndexerImpl;
import com.slytechs.capture.file.indexer.PositionIndexer;
import com.slytechs.capture.file.indexer.RawIndexerImpl;
import com.slytechs.capture.file.indexer.RecordIndexerImpl;
import com.slytechs.capture.file.indexer.RecordPositionIndexer;
import com.slytechs.utils.collection.IOIterator;
import com.slytechs.utils.collection.IOIterator.IteratorAdapter;
import com.slytechs.utils.io.IORuntimeException;
import com.slytechs.utils.number.Version;
/**
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
public abstract class AbstractFile<T extends FilePacket, R extends Record, B extends BlockRecord>
implements FileCapture<T>, RawIteratorBuilder {
protected B block;
private DefaultCaptureDevice captureDevice;
public FileEditor editor;
protected final Filter<ProtocolFilterTarget> filter;
private final HeaderReader headerReader;
private SoftReference<PositionIndexer> indexer;
@SuppressWarnings("unused")
private final Log logger;
public long packetCount = -1;
/**
* @param logger TODO
* @param filter
*/
public AbstractFile(Log logger,
Filter<ProtocolFilterTarget> filter, HeaderReader headerReader) {
this.logger = logger;
this.filter = filter;
this.headerReader = headerReader;
}
public void abortChanges() throws IOException {
editor.abortChanges();
}
public void close() throws IOException {
if (logger.isDebugEnabled()) {
logger.debug(editor.getFlexRegion().toString());
}
editor.close();
}
/**
* Counts all packets very fast using RecordChannelReader parser.
*
* @return number of packet records within the channel
* @throws IOException
* any IO errors
*/
public long countPackets() throws IOException {
PacketIterator<? extends CapturePacket> i = getPacketIterator();
long count = 0;
long old = 0;
while (i.hasNext()) {
old = i.getPosition();
i.skip();
if (old == i.getPosition()) {
throw new IOException("0 length record at [" + old
+ "]. Unable to advance to the next record.");
}
count++;
}
return count;
}
protected abstract PacketIterator<T> createPacketIterator(
final RawIterator raw) throws IOException;
public abstract RawIterator createRawIterator(
Filter<RecordFilterTarget> filter) throws IOException;
public void flush() throws IOException {
editor.flush();
}
public B getBlockRecord() {
return this.block;
}
public final DefaultCaptureDevice getCaptureDevice() {
return this.captureDevice;
}
public File getFile() {
return editor.getFile();
}
/**
* @return
*/
public FileEditor getFileEditor() {
return this.editor;
}
public Filter<ProtocolFilterTarget> getFilter() {
return filter;
}
public long getLength() {
return this.editor.getLength();
}
public long getPacketCount() throws IOException {
if (packetCount == -1) {
packetCount = countPackets();
}
return packetCount;
}
public long getPacketCount(PacketCounterModel model) throws IOException {
switch (model) {
case RealCount:
return getPacketCount();
default:
throw new UnsupportedOperationException("Model not implemented yet");
}
}
public PacketIndexer<T> getPacketIndexer() throws IOException {
final PositionIndexer indexer = this.getPositionIndexer();
final PacketIterator<T> packets = this.getPacketIterator();
return new PacketIndexerImpl<T>(indexer, packets);
}
public PacketIterator<T> getPacketIterator() throws IOException {
final RawIterator raw;
if (filter != null) {
final Filter<RecordFilterTarget> filter = headerReader.asRecordFilter(
this.filter, getCaptureDevice().getLinkType());
raw = getRawIterator(filter);
} else {
raw = getRawIterator();
}
return createPacketIterator(raw);
}
/**
* Caches an indexer and creates a new instance if one is not cached.
*
* @return position indexer for all records
* @throws IOException
* any IO errors
*/
public PositionIndexer getPositionIndexer() throws IOException {
if (this.indexer == null || this.indexer.get() == null) {
this.indexer = new SoftReference<PositionIndexer>(
new RecordPositionIndexer(this.editor.getFlexRegion()));
}
return this.indexer.get();
}
public RawIndexer getRawIndexer() throws IOException {
final PositionIndexer indexer = this.getPositionIndexer();
final RawIterator raw = this.getRawIterator();
return new RawIndexerImpl(raw, indexer);
}
public RawIterator getRawIterator() throws IOException {
return getRawIterator(null);
}
public RawIterator getRawIterator(Filter<RecordFilterTarget> filter)
throws IOException {
return createRawIterator(filter);
}
@SuppressWarnings("unchecked")
public RecordIndexer<R> getRecordIndexer() throws IOException {
final PositionIndexer indexer = this.getPositionIndexer();
RecordIterator<R> records = (RecordIterator<R>) this.getRecordIterator();
return new RecordIndexerImpl<R>(indexer, records);
}
public CaptureType getType() {
return CaptureType.FileCapture;
}
public Version getVersion() throws IOException {
return this.block.getVersion();
}
public boolean isEmpty() throws IOException {
return editor.getLength() <= 24;
}
public boolean isMutable() {
return editor.isMutable();
}
public boolean isOpen() {
return editor.isOpen();
}
public Iterator<T> iterator() {
try {
final IOIterator<T> i = this.getPacketIterator();
return new IteratorAdapter<T>(i);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
/**
* @param device
*/
protected void setCaptureDevice(DefaultCaptureDevice device) {
this.captureDevice = device;
}
public String toString() {
return editor.getFlexRegion().toString();
}
}