001: /*
002: * @(#)ConvertSingleLog.java
003: *
004: * Copyright (C) 2004 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.codecoverage.v2.util;
028:
029: import net.sourceforge.groboutils.codecoverage.v2.IChannelLogger;
030: import java.io.Reader;
031: import java.io.BufferedReader;
032: import java.io.IOException;
033:
034: /**
035: * A way to convert the single log style (not necessarily a file), and outputs
036: * it to a channel logger. This converter handles multiple channels.
037: * <p>
038: * As of 2004-Jun-03, the format has changed.
039: *
040: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
041: * @version $Date: 2004/07/07 09:39:11 $
042: * @since April 16, 2004
043: */
044: public class ConvertSingleLog {
045: private IChannelLogger channels[];
046:
047: /**
048: * Create a new converter, using the given initialized loggers as the
049: * output channels. The order matters: each logger index refers to
050: * that specific channel index; so ch[1] refers to channel 1.
051: *
052: * @param ch the channels to output the single log to.
053: * @exception IllegalArgumentException if <tt>ch</tt> or any entry inside
054: * <tt>ch</tt> is null, or if the length of <tt>ch</tt> is <tt>0</tt>.
055: */
056: public ConvertSingleLog(IChannelLogger ch[]) {
057: if (ch == null) {
058: throw new IllegalArgumentException("no null args");
059: }
060:
061: int len = ch.length;
062: if (len <= 0) {
063: throw new IllegalArgumentException(
064: "must pass at least one channel");
065: }
066: this .channels = new IChannelLogger[len];
067: for (int i = 0; i < len; ++i) {
068: if (ch[i] == null) {
069: throw new IllegalArgumentException("channel " + i
070: + " is null");
071: }
072: this .channels[i] = ch[i];
073: }
074: }
075:
076: /**
077: * Loads all data from the given reader and parses it out to the
078: * channels. The reader is closed on return.
079: *
080: * @exception IOException if there is an I/O error reading from <tt>r</tt>.
081: * @exception IllegalArgumentException if the reader is <tt>null</tt>.
082: */
083: public void read(Reader r, boolean ignoreFormatErrors)
084: throws IOException {
085: if (r == null) {
086: throw new IllegalArgumentException("no null args");
087: }
088:
089: BufferedReader br = new BufferedReader(r);
090: try {
091: String line;
092: while ((line = br.readLine()) != null) {
093: //System.out.println("-- processing line ["+line+"]");
094: processLine(line, ignoreFormatErrors);
095: }
096: } finally {
097: br.close();
098: r.close();
099: }
100: }
101:
102: /**
103: * Process a single line from the single file. Invalid formatted lines
104: * will cause an I/O exception. Blank lines are ignored. Whitespace
105: * is also ignored.
106: *
107: * @param line the input line
108: * @exception IOException if there's a problem with the format of the line,
109: * or if <tt>line</tt> is <tt>null</tt>.
110: */
111: public void processLine(String line, boolean ignoreFormatErrors)
112: throws IOException {
113: if (line == null) {
114: throw new IOException("End of stream: line is null");
115: }
116: line = line.trim();
117: if (line.length() <= 0) {
118: // ignore empty lines.
119: return;
120: }
121:
122: try {
123: int pos[] = { 0, 0 };
124: int channel = (int) nextShort(pos, line);
125:
126: // test the channel
127: if (channel < 0) {
128: throw new IOException("Invalid channel: requested "
129: + channel + ", but we're restricted to "
130: + this .channels.length + " channels.");
131: }
132: if (channel >= this .channels.length) {
133: if (ignoreFormatErrors) {
134: return;
135: }
136: // don't ignore the error
137: throw new IOException("Invalid channel: requested "
138: + channel + ", but we're restricted to "
139: + this .channels.length + " channels.");
140: }
141:
142: // process the rest of the line
143: String classID = nextElement(pos, line);
144: String s = lastElement(pos, line);
145: HexUtil.TwoShorts ts = new HexUtil.TwoShorts();
146:
147: // method then mark
148: if (!HexUtil.getInstance().parseTwoHex(s, ts, ' ', 0)) {
149: throw new IOException(
150: "invalid format for hexidecimal [" + line + "]");
151: }
152:
153: // don't cover the line unless there were no format errors
154: //System.out.println("-- Covering channel "+channel+" ["+classID+"]["+ts.a+"]["+ts.b+"]");
155: this .channels[channel].cover(classID, ts.a, ts.b);
156: } catch (IOException ioe) {
157: if (!ignoreFormatErrors) {
158: throw ioe;
159: }
160: // else ignore the errors
161: }
162: }
163:
164: protected String nextElement(int pos[], String line)
165: throws IOException {
166: pos[1] = line.indexOf(',', pos[0]);
167: if (pos[1] <= pos[0]) {
168: throw new IOException("invalid format [" + line + "]");
169: }
170: String ret = line.substring(pos[0], pos[1]).trim();
171: pos[0] = pos[1] + 1;
172: return ret;
173: }
174:
175: protected short nextShort(int pos[], String line)
176: throws IOException {
177: String s = nextElement(pos, line);
178: return parseShort(s, line);
179: }
180:
181: protected String lastElement(int pos[], String line)
182: throws IOException {
183: if (pos[0] >= line.length()) {
184: throw new IOException("invalid format [" + line + "]");
185: }
186: String s = line.substring(pos[0]);
187: return s;
188: }
189:
190: protected short parseShort(String txt, String line)
191: throws IOException {
192: try {
193: return Short.parseShort(txt);
194: } catch (NumberFormatException e) {
195: throw new IOException("invalid format for short [" + line
196: + "]");
197: }
198: }
199: }
|