XrefWriter.java revision 1384
352N/A/*
352N/A * CDDL HEADER START
352N/A *
352N/A * The contents of this file are subject to the terms of the
352N/A * Common Development and Distribution License (the "License").
352N/A * You may not use this file except in compliance with the License.
352N/A *
352N/A * See LICENSE.txt included in this distribution for the specific
352N/A * language governing permissions and limitations under the License.
352N/A *
352N/A * When distributing Covered Code, include this CDDL HEADER in each
352N/A * file and include the License file at LICENSE.txt.
352N/A * If applicable, add the following below this CDDL HEADER, with the
352N/A * fields enclosed by brackets "[]" replaced with your own identifying
352N/A * information: Portions Copyright [yyyy] [name of copyright owner]
352N/A *
352N/A * CDDL HEADER END
352N/A */
352N/A
352N/A/*
1054N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
352N/A * Portions Copyright 2012 Jens Elkner.
352N/A */
352N/Apackage org.opensolaris.opengrok.analysis;
560N/A
921N/Aimport java.io.BufferedOutputStream;
352N/Aimport java.io.File;
560N/Aimport java.io.FileNotFoundException;
480N/Aimport java.io.FileOutputStream;
480N/Aimport java.io.IOException;
352N/Aimport java.io.OutputStream;
352N/Aimport java.io.OutputStreamWriter;
352N/Aimport java.io.RandomAccessFile;
352N/Aimport java.io.Writer;
352N/Aimport java.nio.channels.FileChannel;
560N/Aimport java.util.zip.GZIPOutputStream;
560N/A
480N/Aimport org.opensolaris.opengrok.analysis.FileAnalyzer.Genre;
352N/Aimport org.opensolaris.opengrok.util.IOUtils;
480N/A
592N/A/**
665N/A * An UTF-8 OutputStreamWriter used to write Xref files.
665N/A *
876N/A * @author Jens Elkner
560N/A * @version $Revision$
377N/A */
480N/Apublic class XrefWriter extends Writer {
352N/A private long count;
352N/A private RandomFileOutputStream fos;
352N/A private Writer out;
352N/A private long mark = -1;
352N/A private XrefHeader header;
352N/A
377N/A /**
352N/A * Creates an uncompressed xref output stream by creating/overwriting the
352N/A * file with the given name.
352N/A * @param name name of the file to create/overwrite.
352N/A * @param genre the genre of the data to be written.
352N/A * @throws IOException
352N/A */
861N/A public XrefWriter(String name, Genre genre) throws IOException {
861N/A this(name, genre, true);
352N/A }
352N/A
352N/A /**
352N/A * Creates an [un]compressed xref output stream by creating/overwriting the
352N/A * file with the given name.
352N/A * @param name name of the file to create/overwrite
352N/A * @param genre the genre of the data to be written.
367N/A * @param compress if {@code true} written data gets compressed.
377N/A * @throws IOException
377N/A */
352N/A public XrefWriter(String name, Genre genre, boolean compress) throws IOException {
352N/A this(new File(name), genre, compress);
352N/A }
352N/A
377N/A /**
352N/A * Creates an uncompressed xref output stream by creating/overwriting the
352N/A * given file.
352N/A *
352N/A * @param file file to write
352N/A * @param genre the genre of the data to be written.
352N/A * @throws IOException
352N/A */
365N/A public XrefWriter(File file, Genre genre) throws IOException {
352N/A this(file, genre, false);
352N/A }
352N/A
489N/A private class RandomFileOutputStream extends OutputStream {
377N/A RandomAccessFile raf;
352N/A
352N/A public RandomFileOutputStream(File file) throws FileNotFoundException {
352N/A if (file == null) {
352N/A throw new IllegalArgumentException("null is not allowed");
352N/A }
352N/A raf = new RandomAccessFile(file, "rw");
352N/A }
352N/A
365N/A @Override
365N/A public void write(int b) throws IOException {
365N/A raf.write(b);
365N/A }
365N/A
365N/A @Override
365N/A public void write(byte[] b, int off, int len) throws IOException {
365N/A raf.write(b, off, len);
365N/A }
1024N/A
365N/A @Override
365N/A public void close() {
365N/A // prevent wrapper streams from closing it
365N/A }
365N/A }
480N/A
480N/A /**
480N/A * Creates an [un]compressed xref output stream by creating/overwriting the
480N/A * given file.
1054N/A *
1054N/A * @param file file to write
1054N/A * @param genre the genre of the data to be written.
1054N/A * @param compress if {@code true} written data gets compressed.
1054N/A * @throws IOException
480N/A * @throws FileNotFoundException
480N/A * @see FileOutputStream
480N/A */
480N/A public XrefWriter(File file, Genre genre, boolean compress) throws IOException {
1054N/A super(file);
1054N/A fos = new RandomFileOutputStream(file);
1054N/A header = new XrefHeader(genre, compress);
1054N/A header.write(fos);
1054N/A out = new OutputStreamWriter(compress
1054N/A ? new GZIPOutputStream(fos, 4096)
1054N/A : new BufferedOutputStream(fos, 16384), "UTF-8");
1054N/A }
1054N/A
480N/A /**
480N/A * Just wraps the given writer. {@link #close()} on this instance gets
480N/A * ignored and thus no header will be written or updated.
480N/A * @param out writer to wrap.
678N/A */
480N/A public XrefWriter(Writer out) {
480N/A super(new Object());
489N/A this.out = out;
480N/A }
489N/A
480N/A /**
665N/A * Get the number of bytes written to the output stream.
665N/A * @return a number >= 0
665N/A * @see FileChannel#position()
807N/A */
665N/A public long getCount() {
665N/A return count;
665N/A }
665N/A
592N/A /**
592N/A * Get the file this instance is writing to.
480N/A * @return {@code null} if this instance wraps another writer, the file
480N/A * used to create this instance otherwise.
480N/A */
480N/A public File getFile() {
480N/A return fos != null ? (File) this.lock : null;
480N/A }
480N/A
480N/A /**
480N/A * {@inheritDoc}
480N/A */
480N/A @Override
480N/A public void write(char[] cbuf, int off, int len) throws IOException {
480N/A out.write(cbuf, off, len);
480N/A count += len;
480N/A }
807N/A
480N/A /**
807N/A * {@inheritDoc}
480N/A */
480N/A @Override
560N/A public void flush() throws IOException {
560N/A out.flush();
560N/A }
560N/A
560N/A /**
560N/A * {@inheritDoc}
560N/A */
560N/A @Override
560N/A public void close() throws IOException {
560N/A if (fos != null) {
921N/A IOUtils.close(out); //flush and release wrapper stream resources
560N/A fos.raf.seek(0);
560N/A header.setSize(count);
560N/A fos.raf.write(header.getBytes().array());
560N/A IOUtils.close(fos.raf);
560N/A }
560N/A out = null;
560N/A }
560N/A
560N/A /**
560N/A * Remember the number of characters currently written to the underlying
593N/A * output stream. NOTE: This method is unsynchronized and thus may return
678N/A * an unexpected value if characters are written concurrently!
593N/A * @return the value of {@link #getCount()}
593N/A */
593N/A public long mark() {
593N/A mark = getCount();
593N/A return mark;
593N/A }
593N/A
593N/A /**
593N/A * Get the number of characters written to the underlying
593N/A * output stream at the last time when {@link #mark()} was called.
593N/A * @return {@code -1} if {@code mark()} has never been called, otherwise
593N/A * the value the last {@code mark()} returned.
593N/A */
593N/A public long getMark() {
593N/A return mark;
593N/A }
593N/A
593N/A /**
876N/A * Set the number of lines written to this stream.
876N/A * @param lines number of lines writen.
876N/A */
876N/A public void setLines(int lines) {
876N/A if (header != null) {
876N/A header.setLines(lines);
876N/A }
876N/A }
876N/A}
876N/A