View Javadoc
1   package com.github.triceo.splitlog;
2   
3   import java.util.Collection;
4   import java.util.Collections;
5   import java.util.LinkedList;
6   import java.util.List;
7   import java.util.concurrent.atomic.AtomicLong;
8   
9   import com.github.triceo.splitlog.api.Message;
10  import com.github.triceo.splitlog.api.TailSplitter;
11  import com.github.triceo.splitlog.splitters.SimpleTailSplitter;
12  
13  final class MessageBuilder {
14  
15      private static final TailSplitter DEFAULT_TAIL_SPLITTER = new SimpleTailSplitter();
16      private static final AtomicLong MESSAGE_ID_GENERATOR = new AtomicLong(0);
17      private static final long NO_MESSAGE_ID_SET = -1;
18  
19      private long futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
20      private final List<String> lines = new LinkedList<String>();
21      private Message previousMessage;
22      private long timestamp;
23  
24      /**
25       * Construct a message builder.
26       *
27       * @param firstLine
28       *            Untreated, unprocessed first line of the new message retrieved
29       *            from the log.
30       */
31      public MessageBuilder(final String firstLine) {
32          if (firstLine == null) {
33              throw new IllegalArgumentException("First line may not be null.");
34          }
35          this.timestamp = System.currentTimeMillis();
36          this.add(firstLine);
37      }
38  
39      /**
40       * Add a bunch of lines that will become part of the message when built.
41       *
42       * @param lines
43       *            Add untreated, unprocessed lines retrieved from the log.
44       * @return This.
45       */
46      public synchronized MessageBuilder add(final Collection<String> lines) {
47          this.lines.addAll(lines);
48          return this;
49      }
50  
51      /**
52       * Add another line that will become part of the message when built.
53       *
54       * @param line
55       *            Add an untreated, unprocessed line retrieved from the log.
56       * @return This.
57       */
58      public MessageBuilder add(final String line) {
59          return this.add(Collections.singletonList(line));
60      }
61  
62      public Message buildFinal() {
63          return this.buildFinal(MessageBuilder.DEFAULT_TAIL_SPLITTER);
64      }
65  
66      public synchronized Message buildFinal(final TailSplitter splitter) {
67          if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
68              // no ID acquired yet
69              this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
70          }
71          final Message msg = new DefaultMessage(this.futureMessageId, this.getLines(), this.getTimestamp(), splitter,
72                  this.previousMessage);
73          // next message will have to acquire new ID
74          this.futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
75          return msg;
76      }
77  
78      public Message buildIntermediate() {
79          return this.buildIntermediate(MessageBuilder.DEFAULT_TAIL_SPLITTER);
80      }
81  
82      public synchronized Message buildIntermediate(final TailSplitter splitter) {
83          if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
84              // no ID acquired yet
85              this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
86          }
87          return new DefaultMessage(this.futureMessageId, this.getLines(), this.getTimestamp(), splitter,
88                  this.previousMessage);
89      }
90  
91      public synchronized Message buildTag() {
92          if (this.futureMessageId == MessageBuilder.NO_MESSAGE_ID_SET) {
93              // no ID acquired yet
94              this.futureMessageId = MessageBuilder.MESSAGE_ID_GENERATOR.getAndIncrement();
95          }
96          final Message msg = new DefaultMessage(this.futureMessageId, this.getFirstLine());
97          // next message will have to acquire new ID
98          this.futureMessageId = MessageBuilder.NO_MESSAGE_ID_SET;
99          return msg;
100     }
101 
102     /**
103      *
104      * @return First line from the server log, no pre-processing.
105      */
106     private String getFirstLine() {
107         return this.lines.get(0);
108     }
109 
110     /**
111      *
112      * @return Raw lines from the server log that have had no pre-processing. This will create a new list every time it
113      * is called, so that {@link #lines} can be modified independently of this new collection's iteration.
114      */
115     private synchronized List<String> getLines() {
116         return Collections.unmodifiableList(new LinkedList<String>(this.lines));
117     }
118 
119     public Message getPreviousMessage() {
120         return this.previousMessage;
121     }
122 
123     public long getTimestamp() {
124         return this.timestamp;
125     }
126 
127     public MessageBuilder setPreviousMessage(final Message previousMessage) {
128         this.previousMessage = previousMessage;
129         return this;
130     }
131 
132     /**
133      * Assign a timestamp to this message.
134      *
135      * @param timestamp
136      *            Timestamp to assign to the message; number of millis since
137      *            January 1st 1970.
138      * @return This.
139      */
140     public MessageBuilder setTimestamp(final long timestamp) {
141         this.timestamp = timestamp;
142         return this;
143     }
144 
145 }