package com.github.triceo.splitlog;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import com.github.triceo.splitlog.api.Message;
import com.github.triceo.splitlog.api.TailSplitter;
import com.github.triceo.splitlog.splitters.SimpleTailSplitter;
final class MessageBuilder {
private static final TailSplitter DEFAULT_TAIL_SPLITTER = new SimpleTailSplitter();
private static final AtomicLong MESSAGE_ID_GENERATOR = new AtomicLong(0);
private static final long NO_MESSAGE_ID_SET = -1;
private long futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
private final List<String> lines = new LinkedList<>();
private Message previousMessage;
private long timestamp;
/**
* Construct a message builder.
*
* @param firstLine
* Untreated, unprocessed first line of the new message retrieved
* from the log.
*/
public MessageBuilder(final String firstLine) {
if (firstLine == null) {
throw new IllegalArgumentException("First line may not be null.");
}
this.timestamp = System.currentTimeMillis();
this.add(firstLine);
}
/**
* Add a bunch of lines that will become part of the message when built.
*
* @param lines
* Add untreated, unprocessed lines retrieved from the log.
* @return This.
*/
public synchronized MessageBuilder add(final Collection<String> lines) {
this.lines.addAll(lines);
return this;
}
/**
* Add another line that will become part of the message when built.
*
* @param line
* Add an untreated, unprocessed line retrieved from the log.
* @return This.
*/
public MessageBuilder add(final String line) {
return this.add(Collections.singletonList(line));
}
public Message buildFinal() {
return this.buildFinal(MessageBuilder.DEFAULT_TAIL_SPLITTER);
}
public synchronized Message buildFinal(final TailSplitter splitter) {
if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
// no ID acquired yet
this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
}
final Message msg = new DefaultMessage(this.futureMessageId, this.getLines(), this.getTimestamp(), splitter,
this.previousMessage);
// next message will have to acquire new ID
this.futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
return msg;
}
public Message buildIntermediate() {
return this.buildIntermediate(MessageBuilder.DEFAULT_TAIL_SPLITTER);
}
public synchronized Message buildIntermediate(final TailSplitter splitter) {
if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
// no ID acquired yet
this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
}
return new DefaultMessage(this.futureMessageId, this.getLines(), this.getTimestamp(), splitter,
this.previousMessage);
}
public synchronized Message buildTag() {
if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
// no ID acquired yet
this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
}
final Message msg = new DefaultMessage(this.futureMessageId, this.getFirstLine());
// next message will have to acquire new ID
this.futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
return msg;
}
/**
*
* @return First line from the server log, no pre-processing.
*/
private String getFirstLine() {
return this.lines.get(0);
}
/**
*
* @return Raw lines from the server log that have had no pre-processing. This will create a new list every time it
* is called, so that {@link #lines} can be modified independently of this new collection's iteration.
*/
private synchronized List<String> getLines() {
return Collections.unmodifiableList(new LinkedList<>(this.lines));
}
public Message getPreviousMessage() {
return this.previousMessage;
}
public long getTimestamp() {
return this.timestamp;
}
public MessageBuilder setPreviousMessage(final Message previousMessage) {
this.previousMessage = previousMessage;
return this;
}
/**
* Assign a timestamp to this message.
*
* @param timestamp
* Timestamp to assign to the message; number of millis since
* January 1st 1970.
* @return This.
*/
public MessageBuilder setTimestamp(final long timestamp) {
this.timestamp = timestamp;
return this;
}
}