http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVParser.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVParser.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVParser.java deleted file mode 100644 index cebf253..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVParser.java +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import static org.apache.qpid.server.management.plugin.csv.Token.Type.TOKEN; - -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.TreeMap; - -/** - * Parses CSV files according to the specified format. - * - * Because CSV appears in many different dialects, the parser supports many formats by allowing the - * specification of a {@link CSVFormat}. - * - * The parser works record wise. It is not possible to go back, once a record has been parsed from the input stream. - * - * <h2>Creating instances</h2> - * <p> - * There are several static factory methods that can be used to create instances for various types of resources: - * </p> - * <ul> - * <li>{@link #parse(File, Charset, CSVFormat)}</li> - * <li>{@link #parse(String, CSVFormat)}</li> - * <li>{@link #parse(URL, Charset, CSVFormat)}</li> - * </ul> - * <p> - * Alternatively parsers can also be created by passing a {@link Reader} directly to the sole constructor. - * - * For those who like fluent APIs, parsers can be created using {@link CSVFormat#parse(Reader)} as a shortcut: - * </p> - * <pre> - * for(CSVRecord record : CSVFormat.EXCEL.parse(in)) { - * ... - * } - * </pre> - * - * <h2>Parsing record wise</h2> - * <p> - * To parse a CSV input from a file, you write: - * </p> - * - * <pre> - * File csvData = new File("/path/to/csv"); - * CSVParser parser = CSVParser.parse(csvData, CSVFormat.RFC4180); - * for (CSVRecord csvRecord : parser) { - * ... - * } - * </pre> - * - * <p> - * This will read the parse the contents of the file using the - * <a href="http://tools.ietf.org/html/rfc4180" target="_blank">RFC 4180</a> format. - * </p> - * - * <p> - * To parse CSV input in a format like Excel, you write: - * </p> - * - * <pre> - * CSVParser parser = CSVParser.parse(csvData, CSVFormat.EXCEL); - * for (CSVRecord csvRecord : parser) { - * ... - * } - * </pre> - * - * <p> - * If the predefined formats don't match the format at hands, custom formats can be defined. More information about - * customising CSVFormats is available in {@link CSVFormat CSVFormat JavaDoc}. - * </p> - * - * <h2>Parsing into memory</h2> - * <p> - * If parsing record wise is not desired, the contents of the input can be read completely into memory. - * </p> - * - * <pre> - * Reader in = new StringReader("a;b\nc;d"); - * CSVParser parser = new CSVParser(in, CSVFormat.EXCEL); - * List<CSVRecord> list = parser.getRecords(); - * </pre> - * - * <p> - * There are two constraints that have to be kept in mind: - * </p> - * - * <ol> - * <li>Parsing into memory starts at the current position of the parser. If you have already parsed records from - * the input, those records will not end up in the in memory representation of your CSV data.</li> - * <li>Parsing into memory may consume a lot of system resources depending on the input. For example if you're - * parsing a 150MB file of CSV data the contents will be read completely into memory.</li> - * </ol> - * - * <h2>Notes</h2> - * <p> - * Internal parser state is completely covered by the format and the reader-state. - * </p> - * - * @see <a href="package-summary.html">package documentation for more details</a> - */ -public final class CSVParser implements Iterable<CSVRecord>, Closeable { - - /** - * Creates a parser for the given {@link File}. - * - * @param file - * a CSV file. Must not be null. - * @param charset - * A Charset - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new parser - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either file or format are null. - * @throws IOException - * If an I/O error occurs - */ - @SuppressWarnings("resource") - public static CSVParser parse(final File file, final Charset charset, final CSVFormat format) throws IOException { - Assertions.notNull(file, "file"); - Assertions.notNull(format, "format"); - return new CSVParser(new InputStreamReader(new FileInputStream(file), charset), format); - } - - /** - * Creates a CSV parser using the given {@link CSVFormat}. - * - * <p> - * If you do not read all records from the given {@code reader}, you should call {@link #close()} on the parser, - * unless you close the {@code reader}. - * </p> - * - * @param inputStream - * an InputStream containing CSV-formatted input. Must not be null. - * @param charset - * a Charset. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new CSVParser configured with the given reader and format. - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either reader or format are null. - * @throws IOException - * If there is a problem reading the header or skipping the first record - * @since 1.5 - */ - @SuppressWarnings("resource") - public static CSVParser parse(final InputStream inputStream, final Charset charset, final CSVFormat format) - throws IOException { - Assertions.notNull(inputStream, "inputStream"); - Assertions.notNull(format, "format"); - return parse(new InputStreamReader(inputStream, charset), format); - } - - /** - * Creates a parser for the given {@link Path}. - * - * @param path - * a CSV file. Must not be null. - * @param charset - * A Charset - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new parser - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either file or format are null. - * @throws IOException - * If an I/O error occurs - * @since 1.5 - */ - public static CSVParser parse(final Path path, final Charset charset, final CSVFormat format) throws IOException { - Assertions.notNull(path, "path"); - Assertions.notNull(format, "format"); - return parse(Files.newBufferedReader(path, charset), format); - } - - /** - * Creates a CSV parser using the given {@link CSVFormat} - * - * <p> - * If you do not read all records from the given {@code reader}, you should call {@link #close()} on the parser, - * unless you close the {@code reader}. - * </p> - * - * @param reader - * a Reader containing CSV-formatted input. Must not be null. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new CSVParser configured with the given reader and format. - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either reader or format are null. - * @throws IOException - * If there is a problem reading the header or skipping the first record - * @since 1.5 - */ - public static CSVParser parse(final Reader reader, final CSVFormat format) throws IOException { - return new CSVParser(reader, format); - } - - /** - * Creates a parser for the given {@link String}. - * - * @param string - * a CSV string. Must not be null. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new parser - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either string or format are null. - * @throws IOException - * If an I/O error occurs - */ - public static CSVParser parse(final String string, final CSVFormat format) throws IOException { - Assertions.notNull(string, "string"); - Assertions.notNull(format, "format"); - - return new CSVParser(new StringReader(string), format); - } - - /** - * Creates a parser for the given URL. - * - * <p> - * If you do not read all records from the given {@code url}, you should call {@link #close()} on the parser, unless - * you close the {@code url}. - * </p> - * - * @param url - * a URL. Must not be null. - * @param charset - * the charset for the resource. Must not be null. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @return a new parser - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either url, charset or format are null. - * @throws IOException - * If an I/O error occurs - */ - public static CSVParser parse(final URL url, final Charset charset, final CSVFormat format) throws IOException { - Assertions.notNull(url, "url"); - Assertions.notNull(charset, "charset"); - Assertions.notNull(format, "format"); - - return new CSVParser(new InputStreamReader(url.openStream(), charset), format); - } - - // the following objects are shared to reduce garbage - - private final CSVFormat format; - - /** A mapping of column names to column indices */ - private final Map<String, Integer> headerMap; - - private final Lexer lexer; - - /** A record buffer for getRecord(). Grows as necessary and is reused. */ - private final List<String> recordList = new ArrayList<>(); - - /** - * The next record number to assign. - */ - private long recordNumber; - - /** - * Lexer offset when the parser does not start parsing at the beginning of the source. Usually used in combination - * with {@link #recordNumber}. - */ - private final long characterOffset; - - private final Token reusableToken = new Token(); - - /** - * Customized CSV parser using the given {@link CSVFormat} - * - * <p> - * If you do not read all records from the given {@code reader}, you should call {@link #close()} on the parser, - * unless you close the {@code reader}. - * </p> - * - * @param reader - * a Reader containing CSV-formatted input. Must not be null. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either reader or format are null. - * @throws IOException - * If there is a problem reading the header or skipping the first record - */ - public CSVParser(final Reader reader, final CSVFormat format) throws IOException { - this(reader, format, 0, 1); - } - - /** - * Customized CSV parser using the given {@link CSVFormat} - * - * <p> - * If you do not read all records from the given {@code reader}, you should call {@link #close()} on the parser, - * unless you close the {@code reader}. - * </p> - * - * @param reader - * a Reader containing CSV-formatted input. Must not be null. - * @param format - * the CSVFormat used for CSV parsing. Must not be null. - * @param characterOffset - * Lexer offset when the parser does not start parsing at the beginning of the source. - * @param recordNumber - * The next record number to assign - * @throws IllegalArgumentException - * If the parameters of the format are inconsistent or if either reader or format are null. - * @throws IOException - * If there is a problem reading the header or skipping the first record - * @since 1.1 - */ - @SuppressWarnings("resource") - public CSVParser(final Reader reader, final CSVFormat format, final long characterOffset, final long recordNumber) - throws IOException { - Assertions.notNull(reader, "reader"); - Assertions.notNull(format, "format"); - - this.format = format; - this.lexer = new Lexer(format, new ExtendedBufferedReader(reader)); - this.headerMap = this.initializeHeader(); - this.characterOffset = characterOffset; - this.recordNumber = recordNumber - 1; - } - - private void addRecordValue(final boolean lastRecord) { - final String input = this.reusableToken.content.toString(); - final String inputClean = this.format.getTrim() ? input.trim() : input; - if (lastRecord && inputClean.isEmpty() && this.format.getTrailingDelimiter()) { - return; - } - final String nullString = this.format.getNullString(); - this.recordList.add(inputClean.equals(nullString) ? null : inputClean); - } - - /** - * Closes resources. - * - * @throws IOException - * If an I/O error occurs - */ - @Override - public void close() throws IOException { - if (this.lexer != null) { - this.lexer.close(); - } - } - - /** - * Returns the current line number in the input stream. - * - * <p> - * <strong>ATTENTION:</strong> If your CSV input has multi-line values, the returned number does not correspond to - * the record number. - * </p> - * - * @return current line number - */ - public long getCurrentLineNumber() { - return this.lexer.getCurrentLineNumber(); - } - - /** - * Gets the first end-of-line string encountered. - * - * @return the first end-of-line string - * @since 1.5 - */ - public String getFirstEndOfLine() { - return lexer.getFirstEol(); - } - - /** - * Returns a copy of the header map that iterates in column order. - * <p> - * The map keys are column names. The map values are 0-based indices. - * </p> - * @return a copy of the header map that iterates in column order. - */ - public Map<String, Integer> getHeaderMap() { - return this.headerMap == null ? null : new LinkedHashMap<>(this.headerMap); - } - - /** - * Returns the current record number in the input stream. - * - * <p> - * <strong>ATTENTION:</strong> If your CSV input has multi-line values, the returned number does not correspond to - * the line number. - * </p> - * - * @return current record number - */ - public long getRecordNumber() { - return this.recordNumber; - } - - /** - * Parses the CSV input according to the given format and returns the content as a list of - * {@link CSVRecord CSVRecords}. - * - * <p> - * The returned content starts at the current parse-position in the stream. - * </p> - * - * @return list of {@link CSVRecord CSVRecords}, may be empty - * @throws IOException - * on parse error or input read-failure - */ - public List<CSVRecord> getRecords() throws IOException { - CSVRecord rec; - final List<CSVRecord> records = new ArrayList<>(); - while ((rec = this.nextRecord()) != null) { - records.add(rec); - } - return records; - } - - /** - * Initializes the name to index mapping if the format defines a header. - * - * @return null if the format has no header. - * @throws IOException if there is a problem reading the header or skipping the first record - */ - private Map<String, Integer> initializeHeader() throws IOException { - Map<String, Integer> hdrMap = null; - final String[] formatHeader = this.format.getHeader(); - if (formatHeader != null) { - hdrMap = this.format.getIgnoreHeaderCase() ? - new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER) : - new LinkedHashMap<String, Integer>(); - - String[] headerRecord = null; - if (formatHeader.length == 0) { - // read the header from the first line of the file - final CSVRecord nextRecord = this.nextRecord(); - if (nextRecord != null) { - headerRecord = nextRecord.values(); - } - } else { - if (this.format.getSkipHeaderRecord()) { - this.nextRecord(); - } - headerRecord = formatHeader; - } - - // build the name to index mappings - if (headerRecord != null) { - for (int i = 0; i < headerRecord.length; i++) { - final String header = headerRecord[i]; - final boolean containsHeader = hdrMap.containsKey(header); - final boolean emptyHeader = header == null || header.trim().isEmpty(); - if (containsHeader && (!emptyHeader || !this.format.getAllowMissingColumnNames())) { - throw new IllegalArgumentException("The header contains a duplicate name: \"" + header + - "\" in " + Arrays.toString(headerRecord)); - } - hdrMap.put(header, Integer.valueOf(i)); - } - } - } - return hdrMap; - } - - /** - * Gets whether this parser is closed. - * - * @return whether this parser is closed. - */ - public boolean isClosed() { - return this.lexer.isClosed(); - } - - /** - * Returns an iterator on the records. - * - * <p> - * An {@link IOException} caught during the iteration are re-thrown as an - * {@link IllegalStateException}. - * </p> - * <p> - * If the parser is closed a call to {@link Iterator#next()} will throw a - * {@link NoSuchElementException}. - * </p> - */ - @Override - public Iterator<CSVRecord> iterator() { - return new Iterator<CSVRecord>() { - private CSVRecord current; - - private CSVRecord getNextRecord() { - try { - return CSVParser.this.nextRecord(); - } catch (final IOException e) { - throw new IllegalStateException( - e.getClass().getSimpleName() + " reading next record: " + e.toString(), e); - } - } - - @Override - public boolean hasNext() { - if (CSVParser.this.isClosed()) { - return false; - } - if (this.current == null) { - this.current = this.getNextRecord(); - } - - return this.current != null; - } - - @Override - public CSVRecord next() { - if (CSVParser.this.isClosed()) { - throw new NoSuchElementException("CSVParser has been closed"); - } - CSVRecord next = this.current; - this.current = null; - - if (next == null) { - // hasNext() wasn't called before - next = this.getNextRecord(); - if (next == null) { - throw new NoSuchElementException("No more CSV records available"); - } - } - - return next; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - /** - * Parses the next record from the current point in the stream. - * - * @return the record as an array of values, or {@code null} if the end of the stream has been reached - * @throws IOException - * on parse error or input read-failure - */ - CSVRecord nextRecord() throws IOException { - CSVRecord result = null; - this.recordList.clear(); - StringBuilder sb = null; - final long startCharPosition = lexer.getCharacterPosition() + this.characterOffset; - do { - this.reusableToken.reset(); - this.lexer.nextToken(this.reusableToken); - switch (this.reusableToken.type) { - case TOKEN: - this.addRecordValue(false); - break; - case EORECORD: - this.addRecordValue(true); - break; - case EOF: - if (this.reusableToken.isReady) { - this.addRecordValue(true); - } - break; - case INVALID: - throw new IOException("(line " + this.getCurrentLineNumber() + ") invalid parse sequence"); - case COMMENT: // Ignored currently - if (sb == null) { // first comment for this record - sb = new StringBuilder(); - } else { - sb.append(Constants.LF); - } - sb.append(this.reusableToken.content); - this.reusableToken.type = TOKEN; // Read another token - break; - default: - throw new IllegalStateException("Unexpected Token type: " + this.reusableToken.type); - } - } while (this.reusableToken.type == TOKEN); - - if (!this.recordList.isEmpty()) { - this.recordNumber++; - final String comment = sb == null ? null : sb.toString(); - result = new CSVRecord(this.recordList.toArray(new String[this.recordList.size()]), this.headerMap, comment, - this.recordNumber, startCharPosition); - } - return result; - } - -}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVPrinter.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVPrinter.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVPrinter.java deleted file mode 100644 index 494e445..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVPrinter.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import static org.apache.qpid.server.management.plugin.csv.Constants.CR; -import static org.apache.qpid.server.management.plugin.csv.Constants.LF; -import static org.apache.qpid.server.management.plugin.csv.Constants.SP; - -import java.io.Closeable; -import java.io.Flushable; -import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * Prints values in a CSV format. - */ -public final class CSVPrinter implements Flushable, Closeable { - - /** The place that the values get written. */ - private final Appendable out; - private final CSVFormat format; - - /** True if we just began a new record. */ - private boolean newRecord = true; - - /** - * Creates a printer that will print values to the given stream following the CSVFormat. - * <p> - * Currently, only a pure encapsulation format or a pure escaping format is supported. Hybrid formats (encapsulation - * and escaping with a different character) are not supported. - * </p> - * - * @param out - * stream to which to print. Must not be null. - * @param format - * the CSV format. Must not be null. - * @throws IOException - * thrown if the optional header cannot be printed. - * @throws IllegalArgumentException - * thrown if the parameters of the format are inconsistent or if either out or format are null. - */ - public CSVPrinter(final Appendable out, final CSVFormat format) throws IOException { - Assertions.notNull(out, "out"); - Assertions.notNull(format, "format"); - - this.out = out; - this.format = format; - // TODO: Is it a good idea to do this here instead of on the first call to a print method? - // It seems a pain to have to track whether the header has already been printed or not. - if (format.getHeaderComments() != null) { - for (final String line : format.getHeaderComments()) { - if (line != null) { - this.printComment(line); - } - } - } - if (format.getHeader() != null && !format.getSkipHeaderRecord()) { - this.printRecord((Object[]) format.getHeader()); - } - } - - // ====================================================== - // printing implementation - // ====================================================== - - @Override - public void close() throws IOException { - close(false); - } - - /** - * Closes the underlying stream with an optional flush first. - * @param flush whether to flush before the actual close. - * - * @throws IOException - * If an I/O error occurs - * @since 1.6 - */ - public void close(final boolean flush) throws IOException { - if (flush || format.getAutoFlush()) { - if (out instanceof Flushable) { - ((Flushable) out).flush(); - } - } - if (out instanceof Closeable) { - ((Closeable) out).close(); - } - } - - /** - * Flushes the underlying stream. - * - * @throws IOException - * If an I/O error occurs - */ - @Override - public void flush() throws IOException { - if (out instanceof Flushable) { - ((Flushable) out).flush(); - } - } - - /** - * Gets the target Appendable. - * - * @return the target Appendable. - */ - public Appendable getOut() { - return this.out; - } - - /** - * Prints the string as the next value on the line. The value will be escaped or encapsulated as needed. - * - * @param value - * value to be output. - * @throws IOException - * If an I/O error occurs - */ - public void print(final Object value) throws IOException { - format.print(value, out, newRecord); - newRecord = false; - } - - /** - * Prints a comment on a new line among the delimiter separated values. - * - * <p> - * Comments will always begin on a new line and occupy a least one full line. The character specified to start - * comments and a space will be inserted at the beginning of each new line in the comment. - * </p> - * - * If comments are disabled in the current CSV format this method does nothing. - * - * @param comment - * the comment to output - * @throws IOException - * If an I/O error occurs - */ - public void printComment(final String comment) throws IOException { - if (!format.isCommentMarkerSet()) { - return; - } - if (!newRecord) { - println(); - } - out.append(format.getCommentMarker().charValue()); - out.append(SP); - for (int i = 0; i < comment.length(); i++) { - final char c = comment.charAt(i); - switch (c) { - case CR: - if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) { - i++; - } - //$FALL-THROUGH$ break intentionally excluded. - case LF: - println(); - out.append(format.getCommentMarker().charValue()); - out.append(SP); - break; - default: - out.append(c); - break; - } - } - println(); - } - - /** - * Outputs the record separator. - * - * @throws IOException - * If an I/O error occurs - */ - public void println() throws IOException { - format.println(out); - newRecord = true; - } - - /** - * Prints the given values a single record of delimiter separated values followed by the record separator. - * - * <p> - * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record - * separator to the output after printing the record, so there is no need to call {@link #println()}. - * </p> - * - * @param values - * values to output. - * @throws IOException - * If an I/O error occurs - */ - public void printRecord(final Iterable<?> values) throws IOException { - for (final Object value : values) { - print(value); - } - println(); - } - - /** - * Prints the given values a single record of delimiter separated values followed by the record separator. - * - * <p> - * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record - * separator to the output after printing the record, so there is no need to call {@link #println()}. - * </p> - * - * @param values - * values to output. - * @throws IOException - * If an I/O error occurs - */ - public void printRecord(final Object... values) throws IOException { - format.printRecord(out, values); - newRecord = true; - } - - /** - * Prints all the objects in the given collection handling nested collections/arrays as records. - * - * <p> - * If the given collection only contains simple objects, this method will print a single record like - * {@link #printRecord(Iterable)}. If the given collections contains nested collections/arrays those nested elements - * will each be printed as records using {@link #printRecord(Object...)}. - * </p> - * - * <p> - * Given the following data structure: - * </p> - * - * <pre> - * <code> - * List<String[]> data = ... - * data.add(new String[]{ "A", "B", "C" }); - * data.add(new String[]{ "1", "2", "3" }); - * data.add(new String[]{ "A1", "B2", "C3" }); - * </code> - * </pre> - * - * <p> - * Calling this method will print: - * </p> - * - * <pre> - * <code> - * A, B, C - * 1, 2, 3 - * A1, B2, C3 - * </code> - * </pre> - * - * @param values - * the values to print. - * @throws IOException - * If an I/O error occurs - */ - public void printRecords(final Iterable<?> values) throws IOException { - for (final Object value : values) { - if (value instanceof Object[]) { - this.printRecord((Object[]) value); - } else if (value instanceof Iterable) { - this.printRecord((Iterable<?>) value); - } else { - this.printRecord(value); - } - } - } - - /** - * Prints all the objects in the given array handling nested collections/arrays as records. - * - * <p> - * If the given array only contains simple objects, this method will print a single record like - * {@link #printRecord(Object...)}. If the given collections contains nested collections/arrays those nested - * elements will each be printed as records using {@link #printRecord(Object...)}. - * </p> - * - * <p> - * Given the following data structure: - * </p> - * - * <pre> - * <code> - * String[][] data = new String[3][] - * data[0] = String[]{ "A", "B", "C" }; - * data[1] = new String[]{ "1", "2", "3" }; - * data[2] = new String[]{ "A1", "B2", "C3" }; - * </code> - * </pre> - * - * <p> - * Calling this method will print: - * </p> - * - * <pre> - * <code> - * A, B, C - * 1, 2, 3 - * A1, B2, C3 - * </code> - * </pre> - * - * @param values - * the values to print. - * @throws IOException - * If an I/O error occurs - */ - public void printRecords(final Object... values) throws IOException { - for (final Object value : values) { - if (value instanceof Object[]) { - this.printRecord((Object[]) value); - } else if (value instanceof Iterable) { - this.printRecord((Iterable<?>) value); - } else { - this.printRecord(value); - } - } - } - - /** - * Prints all the objects in the given JDBC result set. - * - * @param resultSet - * result set the values to print. - * @throws IOException - * If an I/O error occurs - * @throws SQLException - * if a database access error occurs - */ - public void printRecords(final ResultSet resultSet) throws SQLException, IOException { - final int columnCount = resultSet.getMetaData().getColumnCount(); - while (resultSet.next()) { - for (int i = 1; i <= columnCount; i++) { - print(resultSet.getObject(i)); - } - println(); - } - } -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVRecord.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVRecord.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVRecord.java deleted file mode 100644 index e36bfbb..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/CSVRecord.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * A CSV record parsed from a CSV file. - */ -public final class CSVRecord implements Serializable, Iterable<String> { - - private static final String[] EMPTY_STRING_ARRAY = new String[0]; - - private static final long serialVersionUID = 1L; - - private final long characterPosition; - - /** The accumulated comments (if any) */ - private final String comment; - - /** The column name to index mapping. */ - private final Map<String, Integer> mapping; - - /** The record number. */ - private final long recordNumber; - - /** The values of the record */ - private final String[] values; - - CSVRecord(final String[] values, final Map<String, Integer> mapping, final String comment, final long recordNumber, - final long characterPosition) { - this.recordNumber = recordNumber; - this.values = values != null ? values : EMPTY_STRING_ARRAY; - this.mapping = mapping; - this.comment = comment; - this.characterPosition = characterPosition; - } - - /** - * Returns a value by {@link Enum}. - * - * @param e - * an enum - * @return the String at the given enum String - */ - public String get(final Enum<?> e) { - return get(e.toString()); - } - - /** - * Returns a value by index. - * - * @param i - * a column index (0-based) - * @return the String at the given index - */ - public String get(final int i) { - return values[i]; - } - - /** - * Returns a value by name. - * - * @param name - * the name of the column to be retrieved. - * @return the column value, maybe null depending on {@link CSVFormat#getNullString()}. - * @throws IllegalStateException - * if no header mapping was provided - * @throws IllegalArgumentException - * if {@code name} is not mapped or if the record is inconsistent - * @see #isConsistent() - * @see CSVFormat#withNullString(String) - */ - public String get(final String name) { - if (mapping == null) { - throw new IllegalStateException( - "No header mapping was specified, the record values can't be accessed by name"); - } - final Integer index = mapping.get(name); - if (index == null) { - throw new IllegalArgumentException(String.format("Mapping for %s not found, expected one of %s", name, - mapping.keySet())); - } - try { - return values[index.intValue()]; - } catch (final ArrayIndexOutOfBoundsException e) { - throw new IllegalArgumentException(String.format( - "Index for header '%s' is %d but CSVRecord only has %d values!", name, index, - Integer.valueOf(values.length))); - } - } - - /** - * Returns the start position of this record as a character position in the source stream. This may or may not - * correspond to the byte position depending on the character set. - * - * @return the position of this record in the source stream. - */ - public long getCharacterPosition() { - return characterPosition; - } - - /** - * Returns the comment for this record, if any. - * Note that comments are attached to the following record. - * If there is no following record (i.e. the comment is at EOF) - * the comment will be ignored. - * - * @return the comment for this record, or null if no comment for this record is available. - */ - public String getComment() { - return comment; - } - - /** - * Returns the number of this record in the parsed CSV file. - * - * <p> - * <strong>ATTENTION:</strong> If your CSV input has multi-line values, the returned number does not correspond to - * the current line number of the parser that created this record. - * </p> - * - * @return the number of this record. - * @see CSVParser#getCurrentLineNumber() - */ - public long getRecordNumber() { - return recordNumber; - } - - /** - * Tells whether the record size matches the header size. - * - * <p> - * Returns true if the sizes for this record match and false if not. Some programs can export files that fail this - * test but still produce parsable files. - * </p> - * - * @return true of this record is valid, false if not - */ - public boolean isConsistent() { - return mapping == null || mapping.size() == values.length; - } - - /** - * Checks whether this record has a comment, false otherwise. - * Note that comments are attached to the following record. - * If there is no following record (i.e. the comment is at EOF) - * the comment will be ignored. - * - * @return true if this record has a comment, false otherwise - * @since 1.3 - */ - public boolean hasComment() { - return comment != null; - } - - /** - * Checks whether a given column is mapped, i.e. its name has been defined to the parser. - * - * @param name - * the name of the column to be retrieved. - * @return whether a given column is mapped. - */ - public boolean isMapped(final String name) { - return mapping != null && mapping.containsKey(name); - } - - /** - * Checks whether a given columns is mapped and has a value. - * - * @param name - * the name of the column to be retrieved. - * @return whether a given columns is mapped and has a value - */ - public boolean isSet(final String name) { - return isMapped(name) && mapping.get(name).intValue() < values.length; - } - - /** - * Returns an iterator over the values of this record. - * - * @return an iterator over the values of this record. - */ - @Override - public Iterator<String> iterator() { - return toList().iterator(); - } - - /** - * Puts all values of this record into the given Map. - * - * @param map - * The Map to populate. - * @return the given map. - */ - <M extends Map<String, String>> M putIn(final M map) { - if (mapping == null) { - return map; - } - for (final Entry<String, Integer> entry : mapping.entrySet()) { - final int col = entry.getValue().intValue(); - if (col < values.length) { - map.put(entry.getKey(), values[col]); - } - } - return map; - } - - /** - * Returns the number of values in this record. - * - * @return the number of values. - */ - public int size() { - return values.length; - } - - /** - * Converts the values to a List. - * - * TODO: Maybe make this public? - * - * @return a new List - */ - private List<String> toList() { - return Arrays.asList(values); - } - - /** - * Copies this record into a new Map. The new map is not connect - * - * @return A new Map. The map is empty if the record has no headers. - */ - public Map<String, String> toMap() { - return putIn(new HashMap<String, String>(values.length)); - } - - /** - * Returns a string representation of the contents of this record. The result is constructed by comment, mapping, - * recordNumber and by passing the internal values array to {@link Arrays#toString(Object[])}. - * - * @return a String representation of this record. - */ - @Override - public String toString() { - return "CSVRecord [comment=" + comment + ", mapping=" + mapping + - ", recordNumber=" + recordNumber + ", values=" + - Arrays.toString(values) + "]"; - } - - String[] values() { - return values; - } - -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Constants.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Constants.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Constants.java deleted file mode 100644 index 37ec6ae..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Constants.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -/** - * Constants for this package. - */ -final class Constants { - - static final char BACKSLASH = '\\'; - - static final char BACKSPACE = '\b'; - - static final char COMMA = ','; - - /** - * Starts a comment, the remainder of the line is the comment. - */ - static final char COMMENT = '#'; - - static final char CR = '\r'; - - /** RFC 4180 defines line breaks as CRLF */ - static final String CRLF = "\r\n"; - - static final Character DOUBLE_QUOTE_CHAR = Character.valueOf('"'); - - static final String EMPTY = ""; - - /** The end of stream symbol */ - static final int END_OF_STREAM = -1; - - static final char FF = '\f'; - - static final char LF = '\n'; - - /** - * Unicode line separator. - */ - static final String LINE_SEPARATOR = "\u2028"; - - /** - * Unicode next line. - */ - static final String NEXT_LINE = "\u0085"; - - /** - * Unicode paragraph separator. - */ - static final String PARAGRAPH_SEPARATOR = "\u2029"; - - static final char PIPE = '|'; - - /** ASCII record separator */ - static final char RS = 30; - - static final char SP = ' '; - - static final char TAB = '\t'; - - /** Undefined state for the lookahead char */ - static final int UNDEFINED = -2; - - /** ASCII unit separator */ - static final char US = 31; - -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/ExtendedBufferedReader.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/ExtendedBufferedReader.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/ExtendedBufferedReader.java deleted file mode 100644 index 47f8a2e..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/ExtendedBufferedReader.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import static org.apache.qpid.server.management.plugin.csv.Constants.CR; -import static org.apache.qpid.server.management.plugin.csv.Constants.END_OF_STREAM; -import static org.apache.qpid.server.management.plugin.csv.Constants.LF; -import static org.apache.qpid.server.management.plugin.csv.Constants.UNDEFINED; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * A special buffered reader which supports sophisticated read access. - * <p> - * In particular the reader supports a look-ahead option, which allows you to see the next char returned by - * {@link #read()}. This reader also tracks how many characters have been read with {@link #getPosition()}. - * </p> - */ -final class ExtendedBufferedReader extends BufferedReader { - - /** The last char returned */ - private int lastChar = UNDEFINED; - - /** The count of EOLs (CR/LF/CRLF) seen so far */ - private long eolCounter; - - /** The position, which is number of characters read so far */ - private long position; - - private boolean closed; - - /** - * Created extended buffered reader using default buffer-size - */ - ExtendedBufferedReader(final Reader reader) { - super(reader); - } - - @Override - public int read() throws IOException { - final int current = super.read(); - if (current == CR || current == LF && lastChar != CR) { - eolCounter++; - } - lastChar = current; - this.position++; - return lastChar; - } - - /** - * Returns the last character that was read as an integer (0 to 65535). This will be the last character returned by - * any of the read methods. This will not include a character read using the {@link #lookAhead()} method. If no - * character has been read then this will return {@link Constants#UNDEFINED}. If the end of the stream was reached - * on the last read then this will return {@link Constants#END_OF_STREAM}. - * - * @return the last character that was read - */ - int getLastChar() { - return lastChar; - } - - @Override - public int read(final char[] buf, final int offset, final int length) throws IOException { - if (length == 0) { - return 0; - } - - final int len = super.read(buf, offset, length); - - if (len > 0) { - - for (int i = offset; i < offset + len; i++) { - final char ch = buf[i]; - if (ch == LF) { - if (CR != (i > 0 ? buf[i - 1] : lastChar)) { - eolCounter++; - } - } else if (ch == CR) { - eolCounter++; - } - } - - lastChar = buf[offset + len - 1]; - - } else if (len == -1) { - lastChar = END_OF_STREAM; - } - - position += len; - return len; - } - - /** - * Calls {@link BufferedReader#readLine()} which drops the line terminator(s). This method should only be called - * when processing a comment, otherwise information can be lost. - * <p> - * Increments {@link #eolCounter} - * <p> - * Sets {@link #lastChar} to {@link Constants#END_OF_STREAM} at EOF, otherwise to LF - * - * @return the line that was read, or null if reached EOF. - */ - @Override - public String readLine() throws IOException { - final String line = super.readLine(); - - if (line != null) { - lastChar = LF; // needed for detecting start of line - eolCounter++; - } else { - lastChar = END_OF_STREAM; - } - - return line; - } - - /** - * Returns the next character in the current reader without consuming it. So the next call to {@link #read()} will - * still return this value. Does not affect line number or last character. - * - * @return the next character - * - * @throws IOException - * if there is an error in reading - */ - int lookAhead() throws IOException { - super.mark(1); - final int c = super.read(); - super.reset(); - - return c; - } - - /** - * Returns the current line number - * - * @return the current line number - */ - long getCurrentLineNumber() { - // Check if we are at EOL or EOF or just starting - if (lastChar == CR || lastChar == LF || lastChar == UNDEFINED || lastChar == END_OF_STREAM) { - return eolCounter; // counter is accurate - } - return eolCounter + 1; // Allow for counter being incremented only at EOL - } - - /** - * Gets the character position in the reader. - * - * @return the current position in the reader (counting characters, not bytes since this is a Reader) - */ - long getPosition() { - return this.position; - } - - public boolean isClosed() { - return closed; - } - - /** - * Closes the stream. - * - * @throws IOException - * If an I/O error occurs - */ - @Override - public void close() throws IOException { - // Set ivars before calling super close() in case close() throws an IOException. - closed = true; - lastChar = END_OF_STREAM; - super.close(); - } - -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Lexer.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Lexer.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Lexer.java deleted file mode 100644 index 95a3ff0..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Lexer.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import static org.apache.qpid.server.management.plugin.csv.Constants.BACKSPACE; -import static org.apache.qpid.server.management.plugin.csv.Constants.CR; -import static org.apache.qpid.server.management.plugin.csv.Constants.END_OF_STREAM; -import static org.apache.qpid.server.management.plugin.csv.Constants.FF; -import static org.apache.qpid.server.management.plugin.csv.Constants.LF; -import static org.apache.qpid.server.management.plugin.csv.Constants.TAB; -import static org.apache.qpid.server.management.plugin.csv.Constants.UNDEFINED; -import static org.apache.qpid.server.management.plugin.csv.Token.Type.COMMENT; -import static org.apache.qpid.server.management.plugin.csv.Token.Type.EOF; -import static org.apache.qpid.server.management.plugin.csv.Token.Type.EORECORD; -import static org.apache.qpid.server.management.plugin.csv.Token.Type.INVALID; -import static org.apache.qpid.server.management.plugin.csv.Token.Type.TOKEN; - -import java.io.Closeable; -import java.io.IOException; - -/** - * Lexical analyzer. - */ -final class Lexer implements Closeable { - - private static final String CR_STRING = Character.toString(Constants.CR); - private static final String LF_STRING = Character.toString(Constants.LF); - - /** - * Constant char to use for disabling comments, escapes and encapsulation. The value -2 is used because it - * won't be confused with an EOF signal (-1), and because the Unicode value {@code FFFE} would be encoded as two - * chars (using surrogates) and thus there should never be a collision with a real text char. - */ - private static final char DISABLED = '\ufffe'; - - private final char delimiter; - private final char escape; - private final char quoteChar; - private final char commentStart; - - private final boolean ignoreSurroundingSpaces; - private final boolean ignoreEmptyLines; - - /** The input stream */ - private final ExtendedBufferedReader reader; - private String firstEol; - - String getFirstEol(){ - return firstEol; - } - - Lexer(final CSVFormat format, final ExtendedBufferedReader reader) { - this.reader = reader; - this.delimiter = format.getDelimiter(); - this.escape = mapNullToDisabled(format.getEscapeCharacter()); - this.quoteChar = mapNullToDisabled(format.getQuoteCharacter()); - this.commentStart = mapNullToDisabled(format.getCommentMarker()); - this.ignoreSurroundingSpaces = format.getIgnoreSurroundingSpaces(); - this.ignoreEmptyLines = format.getIgnoreEmptyLines(); - } - - /** - * Returns the next token. - * <p> - * A token corresponds to a term, a record change or an end-of-file indicator. - * </p> - * - * @param token - * an existing Token object to reuse. The caller is responsible to initialize the Token. - * @return the next token found - * @throws IOException - * on stream access error - */ - Token nextToken(final Token token) throws IOException { - - // get the last read char (required for empty line detection) - int lastChar = reader.getLastChar(); - - // read the next char and set eol - int c = reader.read(); - /* - * Note: The following call will swallow LF if c == CR. But we don't need to know if the last char was CR or LF - * - they are equivalent here. - */ - boolean eol = readEndOfLine(c); - - // empty line detection: eol AND (last char was EOL or beginning) - if (ignoreEmptyLines) { - while (eol && isStartOfLine(lastChar)) { - // go on char ahead ... - lastChar = c; - c = reader.read(); - eol = readEndOfLine(c); - // reached end of file without any content (empty line at the end) - if (isEndOfFile(c)) { - token.type = EOF; - // don't set token.isReady here because no content - return token; - } - } - } - - // did we reach eof during the last iteration already ? EOF - if (isEndOfFile(lastChar) || !isDelimiter(lastChar) && isEndOfFile(c)) { - token.type = EOF; - // don't set token.isReady here because no content - return token; - } - - if (isStartOfLine(lastChar) && isCommentStart(c)) { - final String line = reader.readLine(); - if (line == null) { - token.type = EOF; - // don't set token.isReady here because no content - return token; - } - final String comment = line.trim(); - token.content.append(comment); - token.type = COMMENT; - return token; - } - - // important: make sure a new char gets consumed in each iteration - while (token.type == INVALID) { - // ignore whitespaces at beginning of a token - if (ignoreSurroundingSpaces) { - while (isWhitespace(c) && !eol) { - c = reader.read(); - eol = readEndOfLine(c); - } - } - - // ok, start of token reached: encapsulated, or token - if (isDelimiter(c)) { - // empty token return TOKEN("") - token.type = TOKEN; - } else if (eol) { - // empty token return EORECORD("") - // noop: token.content.append(""); - token.type = EORECORD; - } else if (isQuoteChar(c)) { - // consume encapsulated token - parseEncapsulatedToken(token); - } else if (isEndOfFile(c)) { - // end of file return EOF() - // noop: token.content.append(""); - token.type = EOF; - token.isReady = true; // there is data at EOF - } else { - // next token must be a simple token - // add removed blanks when not ignoring whitespace chars... - parseSimpleToken(token, c); - } - } - return token; - } - - /** - * Parses a simple token. - * <p/> - * Simple token are tokens which are not surrounded by encapsulators. A simple token might contain escaped - * delimiters (as \, or \;). The token is finished when one of the following conditions become true: - * <ul> - * <li>end of line has been reached (EORECORD)</li> - * <li>end of stream has been reached (EOF)</li> - * <li>an unescaped delimiter has been reached (TOKEN)</li> - * </ul> - * - * @param token - * the current token - * @param ch - * the current character - * @return the filled token - * @throws IOException - * on stream access error - */ - private Token parseSimpleToken(final Token token, int ch) throws IOException { - // Faster to use while(true)+break than while(token.type == INVALID) - while (true) { - if (readEndOfLine(ch)) { - token.type = EORECORD; - break; - } else if (isEndOfFile(ch)) { - token.type = EOF; - token.isReady = true; // There is data at EOF - break; - } else if (isDelimiter(ch)) { - token.type = TOKEN; - break; - } else if (isEscape(ch)) { - final int unescaped = readEscape(); - if (unescaped == END_OF_STREAM) { // unexpected char after escape - token.content.append((char) ch).append((char) reader.getLastChar()); - } else { - token.content.append((char) unescaped); - } - ch = reader.read(); // continue - } else { - token.content.append((char) ch); - ch = reader.read(); // continue - } - } - - if (ignoreSurroundingSpaces) { - trimTrailingSpaces(token.content); - } - - return token; - } - - /** - * Parses an encapsulated token. - * <p/> - * Encapsulated tokens are surrounded by the given encapsulating-string. The encapsulator itself might be included - * in the token using a doubling syntax (as "", '') or using escaping (as in \", \'). Whitespaces before and after - * an encapsulated token are ignored. The token is finished when one of the following conditions become true: - * <ul> - * <li>an unescaped encapsulator has been reached, and is followed by optional whitespace then:</li> - * <ul> - * <li>delimiter (TOKEN)</li> - * <li>end of line (EORECORD)</li> - * </ul> - * <li>end of stream has been reached (EOF)</li> </ul> - * - * @param token - * the current token - * @return a valid token object - * @throws IOException - * on invalid state: EOF before closing encapsulator or invalid character before delimiter or EOL - */ - private Token parseEncapsulatedToken(final Token token) throws IOException { - // save current line number in case needed for IOE - final long startLineNumber = getCurrentLineNumber(); - int c; - while (true) { - c = reader.read(); - - if (isEscape(c)) { - final int unescaped = readEscape(); - if (unescaped == END_OF_STREAM) { // unexpected char after escape - token.content.append((char) c).append((char) reader.getLastChar()); - } else { - token.content.append((char) unescaped); - } - } else if (isQuoteChar(c)) { - if (isQuoteChar(reader.lookAhead())) { - // double or escaped encapsulator -> add single encapsulator to token - c = reader.read(); - token.content.append((char) c); - } else { - // token finish mark (encapsulator) reached: ignore whitespace till delimiter - while (true) { - c = reader.read(); - if (isDelimiter(c)) { - token.type = TOKEN; - return token; - } else if (isEndOfFile(c)) { - token.type = EOF; - token.isReady = true; // There is data at EOF - return token; - } else if (readEndOfLine(c)) { - token.type = EORECORD; - return token; - } else if (!isWhitespace(c)) { - // error invalid char between token and next delimiter - throw new IOException("(line " + getCurrentLineNumber() + - ") invalid char between encapsulated token and delimiter"); - } - } - } - } else if (isEndOfFile(c)) { - // error condition (end of file before end of token) - throw new IOException("(startline " + startLineNumber + - ") EOF reached before encapsulated token finished"); - } else { - // consume character - token.content.append((char) c); - } - } - } - - private char mapNullToDisabled(final Character c) { - return c == null ? DISABLED : c.charValue(); - } - - /** - * Returns the current line number - * - * @return the current line number - */ - long getCurrentLineNumber() { - return reader.getCurrentLineNumber(); - } - - /** - * Returns the current character position - * - * @return the current character position - */ - long getCharacterPosition() { - return reader.getPosition(); - } - - // TODO escape handling needs more work - /** - * Handle an escape sequence. - * The current character must be the escape character. - * On return, the next character is available by calling {@link ExtendedBufferedReader#getLastChar()} - * on the input stream. - * - * @return the unescaped character (as an int) or {@link Constants#END_OF_STREAM} if char following the escape is - * invalid. - * @throws IOException if there is a problem reading the stream or the end of stream is detected: - * the escape character is not allowed at end of stream - */ - int readEscape() throws IOException { - // the escape char has just been read (normally a backslash) - final int ch = reader.read(); - switch (ch) { - case 'r': - return CR; - case 'n': - return LF; - case 't': - return TAB; - case 'b': - return BACKSPACE; - case 'f': - return FF; - case CR: - case LF: - case FF: // TODO is this correct? - case TAB: // TODO is this correct? Do tabs need to be escaped? - case BACKSPACE: // TODO is this correct? - return ch; - case END_OF_STREAM: - throw new IOException("EOF whilst processing escape sequence"); - default: - // Now check for meta-characters - if (isMetaChar(ch)) { - return ch; - } - // indicate unexpected char - available from in.getLastChar() - return END_OF_STREAM; - } - } - - void trimTrailingSpaces(final StringBuilder buffer) { - int length = buffer.length(); - while (length > 0 && Character.isWhitespace(buffer.charAt(length - 1))) { - length = length - 1; - } - if (length != buffer.length()) { - buffer.setLength(length); - } - } - - /** - * Greedily accepts \n, \r and \r\n This checker consumes silently the second control-character... - * - * @return true if the given or next character is a line-terminator - */ - boolean readEndOfLine(int ch) throws IOException { - // check if we have \r\n... - if (ch == CR && reader.lookAhead() == LF) { - // note: does not change ch outside of this method! - ch = reader.read(); - // Save the EOL state - if (firstEol == null) { - this.firstEol = Constants.CRLF; - } - } - // save EOL state here. - if (firstEol == null) { - if (ch == LF) { - this.firstEol = LF_STRING; - } else if (ch == CR) { - this.firstEol = CR_STRING; - } - } - - return ch == LF || ch == CR; - } - - boolean isClosed() { - return reader.isClosed(); - } - - /** - * @return true if the given char is a whitespace character - */ - boolean isWhitespace(final int ch) { - return !isDelimiter(ch) && Character.isWhitespace((char) ch); - } - - /** - * Checks if the current character represents the start of a line: a CR, LF or is at the start of the file. - * - * @param ch the character to check - * @return true if the character is at the start of a line. - */ - boolean isStartOfLine(final int ch) { - return ch == LF || ch == CR || ch == UNDEFINED; - } - - /** - * @return true if the given character indicates end of file - */ - boolean isEndOfFile(final int ch) { - return ch == END_OF_STREAM; - } - - boolean isDelimiter(final int ch) { - return ch == delimiter; - } - - boolean isEscape(final int ch) { - return ch == escape; - } - - boolean isQuoteChar(final int ch) { - return ch == quoteChar; - } - - boolean isCommentStart(final int ch) { - return ch == commentStart; - } - - private boolean isMetaChar(final int ch) { - return ch == delimiter || - ch == escape || - ch == quoteChar || - ch == commentStart; - } - - /** - * Closes resources. - * - * @throws IOException - * If an I/O error occurs - */ - @Override - public void close() throws IOException { - reader.close(); - } -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/QuoteMode.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/QuoteMode.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/QuoteMode.java deleted file mode 100644 index 25c6b31..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/QuoteMode.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.qpid.server.management.plugin.csv; - -/** - * Defines quoting behavior when printing. - */ -public enum QuoteMode { - - /** - * Quotes all fields. - */ - ALL, - - /** - * Quotes all non-null fields. - */ - ALL_NON_NULL, - - /** - * Quotes fields which contain special characters such as a the field delimiter, quote character or any of the - * characters in the line separator string. - */ - MINIMAL, - - /** - * Quotes all non-numeric fields. - */ - NON_NUMERIC, - - /** - * Never quotes fields. When the delimiter occurs in data, the printer prefixes it with the escape character. If the - * escape character is not set, format validation throws an exception. - */ - NONE -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Token.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Token.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Token.java deleted file mode 100644 index c3c94e1..0000000 --- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/csv/Token.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.qpid.server.management.plugin.csv; - -import static org.apache.qpid.server.management.plugin.csv.Token.Type.INVALID; - -/** - * Internal token representation. - * <p/> - * It is used as contract between the lexer and the parser. - */ -final class Token { - - /** length of the initial token (content-)buffer */ - private static final int INITIAL_TOKEN_LENGTH = 50; - - enum Type { - /** Token has no valid content, i.e. is in its initialized state. */ - INVALID, - - /** Token with content, at beginning or in the middle of a line. */ - TOKEN, - - /** Token (which can have content) when the end of file is reached. */ - EOF, - - /** Token with content when the end of a line is reached. */ - EORECORD, - - /** Token is a comment line. */ - COMMENT - } - - /** Token type */ - Token.Type type = INVALID; - - /** The content buffer. */ - final StringBuilder content = new StringBuilder(INITIAL_TOKEN_LENGTH); - - /** Token ready flag: indicates a valid token with content (ready for the parser). */ - boolean isReady; - - void reset() { - content.setLength(0); - type = INVALID; - isReady = false; - } - - /** - * Eases IDE debugging. - * - * @return a string helpful for debugging. - */ - @Override - public String toString() { - return type.name() + " [" + content.toString() + "]"; - } -} http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/8d0e68fc/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/csv/CSVFormatTest.java ---------------------------------------------------------------------- diff --git a/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/csv/CSVFormatTest.java b/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/csv/CSVFormatTest.java new file mode 100644 index 0000000..4e08315 --- /dev/null +++ b/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/csv/CSVFormatTest.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.management.plugin.csv; + +import java.io.StringWriter; +import java.util.Arrays; + +import org.apache.qpid.test.utils.QpidTestCase; + +public class CSVFormatTest extends QpidTestCase +{ + + public void testPrintRecord() throws Exception + { + CSVFormat csvFormat = new CSVFormat(); + final StringWriter out = new StringWriter(); + csvFormat.printRecord(out, Arrays.asList("test", 1, true, "\"quoted\" test")); + assertEquals("Unexpected format", + String.format("%s,%d,%b,%s%s", "test", 1, true, "\"\"\"quoted\"\" test\"", "\r\n"), + out.toString()); + } + + public void testPrintRecords() throws Exception + { + CSVFormat csvFormat = new CSVFormat(); + final StringWriter out = new StringWriter(); + csvFormat.printRecords(out, Arrays.asList(Arrays.asList("test", 1, true, "\"quoted\" test"), + Arrays.asList("delimeter,test", 1.0f, false, + "quote\" in the middle"))); + assertEquals("Unexpected format", + String.format("%s,%d,%b,%s%s%s,%s,%b,%s%s", "test", 1, true, "\"\"\"quoted\"\" test\"", "\r\n", + "\"delimeter,test\"", "1.0", false, "\"quote\"\" in the middle\"", "\r\n"), + out.toString()); + } + + public void testPrintln() throws Exception + { + CSVFormat csvFormat = new CSVFormat(); + final StringWriter out = new StringWriter(); + csvFormat.println(out); + assertEquals("Unexpected new line", "\r\n", out.toString()); + } + + public void testPrint() throws Exception + { + CSVFormat csvFormat = new CSVFormat(); + final StringWriter out = new StringWriter(); + csvFormat.print(out, "test", true); + csvFormat.print(out, 1, false); + csvFormat.print(out, true, false); + csvFormat.print(out, "\"quoted\" test", false); + assertEquals("Unexpected format ", + String.format("%s,%d,%b,%s", "test", 1, true, "\"\"\"quoted\"\" test\""), + out.toString()); + } + + public void testPrintComments() throws Exception + { + CSVFormat csvFormat = new CSVFormat(); + final StringWriter out = new StringWriter(); + csvFormat.printComments(out, "comment1", "comment2"); + assertEquals("Unexpected format of comments", + String.format("# %s%s# %s%s", "comment1", "\r\n", "comment2", "\r\n"), + out.toString()); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org