001: package com.bostechcorp.cbesb.console.help;
002:
003: import java.io.FileNotFoundException;
004: import java.io.IOException;
005: import java.io.RandomAccessFile;
006: import java.util.StringTokenizer;
007:
008: import com.bostechcorp.cbesb.console.common.ServerSideException;
009: import com.bostechcorp.cbesb.console.i18n.ConsoleMessages;
010: import com.google.gwt.core.client.GWT;
011:
012: public class FileHelper {
013:
014: private int numOfLines = 0;
015:
016: private int tempSize = 0;
017:
018: private long lastEnd = 0;
019:
020: private long lastFrom = 0;
021:
022: private String lastString = "";
023:
024: public String tail(String fileName, int lineCount)
025: throws ServerSideException {
026:
027: return tail(fileName, lineCount, 20000);
028: }
029:
030: /**
031: * Given a byte array this method:
032: * a. creates a String out of it
033: * b. reverses the string
034: * c. extracts the lines
035: * d. characters in extracted line will be in reverse order,
036: * so it reverses the line just before storing in Vector.
037: *
038: * On extracting required numer of lines, this method returns TRUE,
039: * Else it returns FALSE.
040: *
041: * @param bytearray
042: * @param lineCount
043: * @param lastNlines
044: * @return
045: */
046:
047: private StringBuffer parseLinesFromLast(byte[] bytearray,
048: int lineCount, StringBuffer oldString) {
049:
050: String lastNChars = new String(bytearray);
051: StringBuffer sb = new StringBuffer(lastNChars);
052: sb.toString();
053: lastNChars = sb.reverse().toString();
054: StringTokenizer tokens = new StringTokenizer(lastNChars, "\n");
055: while (tokens.hasMoreTokens()) {
056: StringBuffer sbLine = new StringBuffer((String) tokens
057: .nextToken());
058: //lastNlines.add(sbLine.reverse().toString());
059: numOfLines++;
060: //if(oldString.equals(""))
061: oldString = oldString.insert(0, "\n");
062: oldString = oldString
063: .insert(0, sbLine.reverse().toString());
064: tempSize = sbLine.toString().length() + 1;
065: if (numOfLines == lineCount) {
066: oldString.length();
067: return oldString;//indicates we got 'lineCount' lines
068: }
069: }
070:
071: /*oldString = oldString.delete(0, tempSize);
072: numOfLines--;*/
073: return oldString; //indicates didn't read 'lineCount' lines
074: }
075:
076: /**
077: * Reads last N lines from the given file. File reading is done in chunks.
078: *
079: * Constraints:
080: * 1 Minimize the number of file reads -- Avoid reading the complete file
081: * to get last few lines.
082: * 2 Minimize the JVM in-memory usage -- Avoid storing the complete file
083: * info in in-memory.
084: *
085: * Approach: Read a chunk of characters from end of file. One chunk should
086: * contain multiple lines. Reverse this chunk and extract the lines.
087: * Repeat this until you get required number of last N lines. In this way
088: * we read and store only the required part of the file.
089: *
090: * 1 Create a RandomAccessFile.
091: * 2 Get the position of last character using (i.e length-1). Let this be curPos.
092: * 3 Move the cursor to fromPos = (curPos - chunkSize). Use seek().
093: * 4 If fromPos is less than or equal to ZERO then go to step-5. Else go to step-6
094: * 5 Read characters from beginning of file to curPos. Go to step-9.
095: * 6 Read 'chunksize' characters from fromPos.
096: * 7 Extract the lines. On reading required N lines go to step-9.
097: * 8 Repeat step 3 to 7 until
098: * a. N lines are read.
099: * OR
100: * b. All lines are read when num of lines in file is less than N.
101: * Last line may be a incomplete, so discard it. Modify curPos appropriately.
102: * 9 Exit. Got N lines or less than that.
103: *
104: * @param fileName
105: * @param lineCount
106: * @param chunkSize
107: * @return
108: */
109:
110: public String tail(String fileName, int lineCount, int chunkSize)
111: throws ServerSideException {
112: //try {
113: RandomAccessFile raf = null;
114: try {
115: raf = new RandomAccessFile(fileName, "r");
116: } catch (FileNotFoundException e) {
117: throw new ServerSideException(((ConsoleMessages) GWT
118: .create(ConsoleMessages.class)).LogFileNotFound(),
119: e);
120: }
121: long beginning = 0;
122:
123: numOfLines = 0;
124: int delta = 0;
125:
126: long totalLen = 0;
127: try {
128: totalLen = raf.length();
129: } catch (IOException e) {
130: throw new ServerSideException(((ConsoleMessages) GWT
131: .create(ConsoleMessages.class)).LogFileNoLength(),
132: e);
133: }
134: if (lastEnd != 0) {
135: if (lastEnd == totalLen) {
136: return "";
137: } else if (lastEnd > totalLen) {
138: beginning = 0;
139: } else {
140: beginning = lastEnd;
141: }
142: // If last time we return some strings, check whether the file is changed or not
143: if (!lastString.equalsIgnoreCase("")) {
144:
145: byte[] bytearray = new byte[lastString.length()];
146: try {
147: raf.seek(lastFrom);
148: raf.readFully(bytearray);
149: } catch (IOException e) {
150: throw new ServerSideException(
151: ((ConsoleMessages) GWT
152: .create(ConsoleMessages.class))
153: .LogFileNotReadable(), e);
154:
155: }
156: String temp = new String(bytearray);
157: if (!lastString.equalsIgnoreCase(temp)) {
158:
159: beginning = 0;
160: }
161: }
162:
163: }
164: long curPos = totalLen;
165: long fromPos;
166: StringBuffer oldStr = new StringBuffer();
167: byte[] bytearray;
168: if (curPos == -1)
169: return null;
170: while (true) {
171: fromPos = curPos - chunkSize;
172:
173: if (fromPos <= beginning) {
174: bytearray = new byte[(int) (curPos - beginning)];
175:
176: try {
177: raf.seek(beginning);
178: raf.readFully(bytearray);
179: } catch (IOException e) {
180: throw new ServerSideException(
181: ((ConsoleMessages) GWT
182: .create(ConsoleMessages.class))
183: .LogFileNotReadable(), e);
184:
185: }
186: lastFrom = beginning;
187: lastString = new String(bytearray);
188: oldStr = parseLinesFromLast(bytearray, lineCount,
189: oldStr);
190:
191: break;
192: } else {
193: bytearray = new byte[chunkSize];
194: try {
195: raf.seek(fromPos);
196: raf.readFully(bytearray);
197: } catch (IOException e) {
198: throw new ServerSideException(
199: ((ConsoleMessages) GWT
200: .create(ConsoleMessages.class))
201: .LogFileNotReadable(), e);
202:
203: }
204: lastFrom = fromPos;
205: lastString = new String(bytearray);
206: oldStr = parseLinesFromLast(bytearray, lineCount,
207: oldStr);
208:
209: oldStr = oldStr.delete(0, tempSize);
210: numOfLines--;
211:
212: if (numOfLines == lineCount) {
213: break;
214: }
215: delta = tempSize - 1;
216: curPos = fromPos + delta;
217: }
218: }
219:
220: int len = oldStr.toString().length();
221: if (len != 0)
222: oldStr.delete(len - 1, len);
223: lastEnd = totalLen;
224: return oldStr.toString();
225:
226: }
227:
228: public long getLastEnd() {
229: return lastEnd;
230: }
231:
232: public void setLastEnd(long lastEnd) {
233: this .lastEnd = lastEnd;
234: }
235:
236: public long getLastFrom() {
237: return lastFrom;
238: }
239:
240: public void setLastFrom(long lastFrom) {
241: this .lastFrom = lastFrom;
242: }
243:
244: public String getLastString() {
245: return lastString;
246: }
247:
248: public void setLastString(String lastString) {
249: this .lastString = lastString;
250: }
251:
252: public void init() {
253: setLastEnd(0);
254: setLastString("");
255: setLastFrom(0);
256: }
257:
258: }
|