Replicating console functionality with a ListView - java

I apologize for not being able to think of a more descriptive title.
I have managed to redirect the system.out to a new ListView via my own OutputStream class Console:
public class Console extends OutputStream {
private ListView<String> output;
public Console(ListView<String> output) {
this.output = output;
}
private void addText(String str) {
Platform.runLater( () -> output.getItems().add(str) );
}
#Override
public void write(int b) throws IOException {
addText(String.valueOf((char) b));
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
addText(new String(b, off, len));
}
#Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
}
Here, I create the console in my controller class. output is the name of the
ListView in my FXML:
private void buildConsole() {
Console console = new Console(output);
PrintStream ps = new PrintStream(console, true);
System.setOut(ps);
System.setErr(ps);
}
Here is where I am testing the output with an event handler that prints the tile coordinates over which my mouse is hovering:
tile.setOnMouseEntered(e -> {
tile.setFill(hoverColor);
showConnections(tile);
gridController.getCoordinateLabel().setText(tile.getVertex().toString());
System.out.print("Tile " + tile.getVertex().toString() + " selected.");
});
Notice that I am using System.out.print() and not println(). This is the output:
If I were to use println():
My ideal behavior is:
system.out.print() - text to be added to the same line.
system.out.println() - text added to the next cell.

Since you are looking for behavior that corresponds to a system or IDE console, that corresponds, in part, to splitting the output into logical units (i.e. "lines") at newline characters. That would happen automatically if you just collected whatever is written and appended it to a text area, so I would encourage you to try that and see. Even if it turns out to be less efficient, it may still be plenty efficient for your purposes.
If you want to proceed with the ListView, however, then your Console class needs to internally buffer the data written to it, scan for newlines, and break up the output into cells at newlines. It create a new cell only when it sees a newline, and in that case include all the buffered text up to, but not including that newline.
Update:
A ByteArrayOutputStream would make a fine buffer. Something like this, for example:
public class Console extends OutputStream {
private ListView<String> output;
private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public Console(ListView<String> output) {
this.output = output;
}
private void addText() throws IOException {
String text = buffer.toString("UTF-8");
buffer.reset();
Platform.runLater( () -> output.getItems().add(text) );
}
#Override
public void write(int b) throws IOException {
if (b == '\n') {
addText();
} else {
buffer.write(b);
}
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
int bound = off + len;
for (int i = off; i < bound; i++) {
if (b[i] == '\n') {
buffer.write(b, off, i - off);
addText();
off = i + 1;
}
}
assert(off <= bound);
buffer.write(b, off, bound - off);
}
#Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
#Override
public void flush() throws IOException {
// outputs all currently buffered data as a new cell, without receiving
// a newline as otherwise is required for that
addText();
}
#Override
public void close() throws IOException {
flush();
buffer.close();
}
}

Related

How to get the intermediate compressed size using GZipOutputStream? [duplicate]

I have a BufferedWriter as shown below:
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream( hdfs.create(filepath, true ))));
String line = "text";
writer.write(line);
I want to find out the bytes written to the file with out querying file like
hdfs = FileSystem.get( new URI( "hdfs://localhost:8020" ), configuration );
filepath = new Path("path");
hdfs.getFileStatus(filepath).getLen();
as it will add overhead and I don't want that.
Also I cant do this:
line.getBytes().length;
As it give size before compression.
You can use the CountingOutputStream from Apache commons IO library.
Place it between the GZIPOutputStream and the file Outputstream (hdfs.create(..)).
After writing the content to the file you can read the number of written bytes from the CountingOutputStream instance.
If this isn't too late and you are using 1.7+ and you don't wan't to pull in an entire library like Guava or Commons-IO, you can just extend the GZIPOutputStream and obtain the data from the associated Deflater like so:
public class MyGZIPOutputStream extends GZIPOutputStream {
public MyGZIPOutputStream(OutputStream out) throws IOException {
super(out);
}
public long getBytesRead() {
return def.getBytesRead();
}
public long getBytesWritten() {
return def.getBytesWritten();
}
public void setLevel(int level) {
def.setLevel(level);
}
}
You can make you own descendant of OutputStream and count how many time write method was invoked
This is similar to the response by Olaseni, but I moved the counting into the BufferedOutputStream rather than the GZIPOutputStream, and this is more robust, since def.getBytesRead() in Olaseni's answer is not available after the stream has been closed.
With the implementation below, you can supply your own AtomicLong to the constructor so that you can assign the CountingBufferedOutputStream in a try-with-resources block, but still retrieve the count after the block has exited (i.e. after the file is closed).
public static class CountingBufferedOutputStream extends BufferedOutputStream {
private final AtomicLong bytesWritten;
public CountingBufferedOutputStream(OutputStream out) throws IOException {
super(out);
this.bytesWritten = new AtomicLong();
}
public CountingBufferedOutputStream(OutputStream out, int bufSize) throws IOException {
super(out, bufSize);
this.bytesWritten = new AtomicLong();
}
public CountingBufferedOutputStream(OutputStream out, int bufSize, AtomicLong bytesWritten)
throws IOException {
super(out, bufSize);
this.bytesWritten = bytesWritten;
}
#Override
public void write(byte[] b) throws IOException {
super.write(b);
bytesWritten.addAndGet(b.length);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
super.write(b, off, len);
bytesWritten.addAndGet(len);
}
#Override
public synchronized void write(int b) throws IOException {
super.write(b);
bytesWritten.incrementAndGet();
}
public long getBytesWritten() {
return bytesWritten.get();
}
}

How to sent a result to a file and to output at the same time

This game is like FizzBuzz but with different words as you can see.
I need to print the result of "Nardo" to output(System.out.println) and to file, when called, at the same time.
I made 2 classes one for FizzBuzz game and the other to sent some text into the file. This one works correctly, but I don't know how to combine it with FizzBuzz Class.
I just called the class OutputToFile into the FizzBuzz, but I don't know how to continue.
1) First Class
public class BaroSello {
private OutputToFile outputfile = new OutputToFile();
for(int i=1; i<input; i++){
if ((i % 3 == 0 && i % 5 == 0))
System.out.println("BaroSello");
else if (i % 3 == 0)
System.out.println("Baro");
else if (i % 5 == 0)
System.out.println("Sello");
else if (i%7==0)
// here I need the output to file and to terminal
System.out.println("Nardo");
else
System.out.println(i);
}
}
2) Second Class
public class OutputToFile {
public static void main(String[] args) {
try {
PrintStream myconsole = new PrintStream(new File("/Users/xxx/Desktop/output.txt"));
System.setOut(myconsole);
myconsole.println("hello");
} catch (FileNotFoundException fx) {
System.out.println(fx);
}
}
}
The class below will split the calls you make to a 2 OutputStream's.
For your program, instead of creating a PrintStream from the file, first create a FileOutputStream. Then create a new SplitOutputStream from your FileOutputStream and System.out. With the SplitOutputStream, any single write you make will be written to both the FileOutputStream and System.out. By wrapping a PrintStream over the SplitOutputStream, you can now do println on the PrintStream, and the output will go to both the file and the System.out.
import java.io.*;
public class SplitOutputStream extends OutputStream{
public static void main(String[] args) throws Throwable{
SplitOutputStream split=new SplitOutputStream(
new FileOutputStream("c:\\text.txt"),
System.out
);
PrintStream splitPs=new PrintStream(split);
splitPs.println("some text");
splitPs.flush();
splitPs.close();
//or (not both)
PrintWriter splitPw=new PrintWriter(split);
splitPw.println("some text");
splitPw.flush();
splitPw.close();
}
OutputStream o1;
OutputStream o2;
public SplitOutputStream(OutputStream o1,OutputStream o2){
this.o1=o1;
this.o2=o2;
}
#Override public void write(int b) throws IOException{
o1.write(b);
o2.write(b);
}
#Override public void write(byte[] b,int off,int len) throws IOException{
o1.write(b,off,len);
o2.write(b,off,len);
}
#Override public void flush() throws IOException{
o1.flush();
o2.flush();
}
#Override public void close() throws IOException{
o1.close();
o2.close();
}
}
Or
PrintStream originalSysOut=System.out;
SplitOutputStream split=new SplitOutputStream(
new FileOutputStream("c:\\work\\text.txt"),
originalSysOut
);
PrintStream splitPs=new PrintStream(split,true);
System.setOut(splitPs);
System.out.println("some text");
The code above changes the System.out to output to your file plus the original System.out

Apache Util.copyStream: Stop Stream

Is it possible to stop the bytesTransferred stream for the Apache Util.copyStream function?
long bytesTransferred = Util.copyStream(inputStream, outputStream, 32768, CopyStreamEvent.UNKNOWN_STREAM_SIZE, new CopyStreamListener() {
#Override
public void bytesTransferred(CopyStreamEvent event) {
bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize());
}
#Override
public void bytesTransferred(long totalBytesTransferred, int bytesTransferred,
long streamSize) {
try {
if(true) {
log.info('Stopping');
return; //Cancel
} else {
log.info('Still going');
}
} catch (InterruptedException e) {
// this should not happen!
}
}
});
In this case, what will happen is that I keep getting a Stopping message in my logs. I also tried throwing a new RuntileException instead of returning, and again I get endless Stopping messages. How would I cancel the bytesTransfered in this case?
You could try wrapping the input stream, and overriding the read methods to check for a stop flag. If set, throw an IOException. Example class.
/**
* Wrapped input stream that can be cancelled.
*/
public class WrappedStoppableInputStream extends InputStream
{
private InputStream m_wrappedInputStream;
private boolean m_stop = false;
/**
* Constructor.
* #param inputStream original input stream
*/
public WrappedStoppableInputStream(InputStream inputStream)
{
m_wrappedInputStream = inputStream;
}
/**
* Call to stop reading stream.
*/
public void cancelTransfer()
{
m_stop = true;
}
#Override
public int read() throws IOException
{
if (m_stop)
{
throw new IOException("Stopping stream");
}
return m_wrappedInputStream.read();
}
#Override
public int read(byte[] b) throws IOException
{
if (m_stop)
{
throw new IOException("Stopping stream");
}
return m_wrappedInputStream.read(b);
}
#Override
public int read(byte[] b, int off, int len) throws IOException
{
if (m_stop)
{
throw new IOException("Stopping stream");
}
return m_wrappedInputStream.read(b, off, len);
}
}
I am assuming that the file copying is running inside a thread. So you wrap your input stream with WrappedStoppableInputStream, and pass that to your copy function, to be used instead of the original input stream.

How to redirect javax.mail.Session setDebugOut to log4j logger?

How to redirect javax.mail.Session setDebugOut to log4j logger?
Is it possible to redirect only mailSession debug out to logger?
I mean, there are solutions like
link text
which reassigns all standard output to go to log4j
--System.setOut(new Log4jStream())
Best Regards
Apache Commons Exec library contains useful class LogOutputStream, which you can use for this exact purpose:
LogOutputStream losStdOut = new LogOutputStream() {
#Override
protected void processLine(String line, int level) {
cat.debug(line);
}
};
Session session = Session.getDefaultInstance(new Properties(), null);
session.setDebugOut(new PrintStream(losStdOut));
cat is obviously log4j Category/Appender.
i created an own filteroutputstream (you could also use the org.apache.logging.Logger instead of the SLF)
public class LogStream extends FilterOutputStream
{
private static org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(LogStream.class);
private static final OutputStream bos = new ByteArrayOutputStream();
public LogStream(OutputStream out)
{
// initialize parent with my bytearray (which was never used)
super(bos);
}
#Override
public void flush() throws IOException
{
// this was never called in my test
bos.flush();
if (bos.size() > 0) LOG.info(bos.toString());
bos.reset();
}
#Override
public void write(byte[] b) throws IOException
{
LOG.info(new String(b));
}
#Override
public void write(byte[] b, int off, int len) throws IOException
{
LOG.info(new String(b, off, len));
}
#Override
public void write(int b) throws IOException
{
write(new byte[] { (byte) b });
}
}
then i redirected the javamail to my output
// redirect the output to our logstream
javax.mail.Session def = javax.mail.Session.getDefaultInstance(new Properties());
def.setDebugOut(new PrintStream(new LogStream(null)));
def.setDebug(true);
that did the trick :)
Write your own OutputStream class
and
mailSession.setDebugOut(new PrintStream(your custom aoutput stream object));

Java - Capturing System.err.println or Capturing a PrintStream

Java Newbie question :
I need to capture the text being written to a printStream by a 3rd party component.
The PrintStream is defaulted to System.err, but can be changed to another PrintStream.
Looking through the docs, I couldn't find an easy way to direct the contents of a PrintStream to a string writer / buffer.
Can someone please assist?
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream(pipeOut);
System.setOut(new PrintStream(pipeOut));
// now read from pipeIn
import java.io.*;
public class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("errors.txt");
} catch(IOException ioe) {
System.err.println("redirection not possible: "+ioe);
System.exit(-1);
}
PrintStream ps = new PrintStream(fos);
System.setErr(ps);
System.err.println("goes into file");
}
}
You can create a PrintStream around any other OutputStream.
The simplest way to create one that goes to a buffer in memory would be:
PrintStream p = new PrintStream( new ByteArrayOutputStream() )
Then you could read and reset the contents of the byte array at whatever points you like.
Another possibility would be to use pipes.
InputStream third_party_output = new PipedInputStream();
PrintStream p = new PrintStream( new PipedOutputStream( third_party_output ) );
Then you could read from the third_party_output stream to get the text written by the library.
Are you looking for something like this?
OutputStream redirect = System.err;
PrintStream myPrintStream = new PrintStream(redirect);
myPrintStream.println("hello redirect");
If you can pass myPrintStream to the 3rd party application, you can redirect it anywhere you want.
I use the following class to log System.out and System.err to a set of rotating files (where xxx-001.log is the most recent). It contains a few call to utility methods, which you will need to implement before it will compile - they should be self-explanatory.
import java.io.*;
import java.lang.reflect.*;
public class LoggerOutputStream
extends OutputStream
{
// *****************************************************************************
// INSTANCE PROPERTIES
// *****************************************************************************
private FileOutputStream log=null; // the base output stream
private String fnmBase,fnmExt; // filename base, file extension
private int fnmCount,fnmLast; // count for filename index, last filename used
private int logSize,totWritten; // max log size, current number of bytes written
// *****************************************************************************
// INSTANCE CONSTRUCTORS/INIT/CLOSE/FINALIZE
// *****************************************************************************
public LoggerOutputStream(String baseFilename) throws IOException {
this(baseFilename,".log",2,1024000);
}
public LoggerOutputStream(String baseFilename, String extension) throws IOException {
this(baseFilename,extension,2,1024000);
}
public LoggerOutputStream(String baseFilename, String extension, int numberOfFiles, int maxFileSize) throws IOException {
fnmBase=baseFilename;
if(Character.isLetterOrDigit(fnmBase.charAt(fnmBase.length()-1))) { fnmBase=(fnmBase+"-"); }
fnmExt=extension;
if(!fnmExt.startsWith(".")) { fnmExt=('.'+fnmExt); }
fnmCount=numberOfFiles;
logSize=maxFileSize;
if(fnmCount>MAXLOGS) { fnmCount=MAXLOGS; }
fnmLast=0;
for(int xa=1; xa<=MAXLOGS; xa++) {
if(!new File(constructFilename(xa)).exists()) {
while((--xa)>fnmCount) { IoUtil.deleteFile(constructFilename(xa)); }
fnmLast=xa;
break;
}
}
log=null;
openFile(false);
if(numberOfFiles>MAXLOGS) { System.out.println("** Log File Count Limited To "+MAXLOGS); }
}
public void close() throws IOException {
close(false);
}
private void openFile(boolean ovrflw) throws IOException {
close(true);
if (fnmLast< fnmCount) { fnmLast++; }
else if(fnmLast==fnmCount) { IoUtil.deleteFile(constructFilename(fnmCount)); }
for(int xa=fnmLast; xa>0; xa--) { IoUtil.renameFile(constructFilename(xa-1),constructFilename(xa)); }
log=new FileOutputStream(constructFilename(1));
totWritten=0;
}
private String constructFilename(int index) {
return constructFilename(fnmBase,index,fnmExt);
}
private synchronized void close(boolean ovrflw) throws IOException {
if(log!=null) {
log.flush();
log.close();
log=null;
}
}
// *****************************************************************************
// INSTANCE METHODS - ACCESSORS
// *****************************************************************************
public String getFilename() {
return constructFilename(1);
}
public String getFilename(int idx) {
return constructFilename(idx);
}
public synchronized void cycleLogFile() throws IOException {
openFile(true);
}
// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************
public synchronized void flush() throws IOException {
if(log!=null) {
log.flush();
}
}
public synchronized void write(int val) throws IOException {
if(log!=null) {
log.write(val);
totWritten++;
if(val=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
public synchronized void write(byte[] bytes) throws IOException {
if(log!=null) {
log.write(bytes);
totWritten+=bytes.length;
if(bytes.length>0 && bytes[bytes.length-1]=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
public synchronized void write(byte[] bytes, int str, int len) throws IOException {
if(log!=null) {
log.write(bytes,str,len);
totWritten+=len;
if(bytes.length>(str+len-1) && bytes[str+len-1]=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************
static public final int MAXLOGS=999; // maximum log files allowed
// *****************************************************************************
// STATIC METHODS
// *****************************************************************************
static public String constructFilename(String bas, int idx, String ext) {
if(!bas.endsWith("-") && !bas.endsWith("_") && !bas.endsWith(".")) { bas=(bas+"-"); }
if(!ext.startsWith(".") ) { ext=('.'+ext); }
return (bas+TextUtil.raZeros(idx,3)+ext);
}
} /* END PUBLIC CLASS */

Categories