Redirect java console content on java UI - java

I have a prolog file (Expert System) that I consult from Java using Jpl libraries (org.jpl7.*) and I have an UI where I want to show the output of prolog's queries.
This is my Custom Output Stream that should redirect every console content into my interface (jTextAreaOUTPUT is the place where i redirect the content)
public class CustomOutputStream extends OutputStream {
private JTextArea jTextAreaOUTPUT;
public CustomOutputStream(JTextArea textArea) {
jTextAreaOUTPUT = textArea;
}
#Override
public void write(int b) throws IOException {
// redirects data to the text area
jTextAreaOUTPUT.append(String.valueOf((char)b));
// scrolls the text area to the end of data
jTextAreaOUTPUT.setCaretPosition(jTextAreaOUTPUT.getDocument().getLength());
}
}
This are some lines I have in my Interface Class: this calls the Custom Output Stream methond:
PrintStream printStream = new PrintStream(new CustomOutputStream(jTextAreaOUTPUT), true, "UTF-8");
// keeps reference of standard output stream
PrintStream standardOut = System.out;
System.setOut(printStream);
System.setErr(printStream);
For some strange reasons it doesn't work whith this prolog file (I tried with other and It works): UI freezes and content keeps showing in java console (eclipse).
The Expert System file works with write instruction in Prolog (e.g. write('Lorem Ipsum') )
Why standardOut in never used ? Is it ok declared this way?
Is there a way to force redirect for all the text that should be written in eclipse console?
I also tried to use " write Stream " method in prolog, but (only for this prolog file, maybe due to recursion) UI freezes even though outpus is written on a txt file.

You might need to override the other write functions in outputstream write(byte[] b), write(byte[] b, int off, int len) if the writer doesn't write one character at a time
To override the other write functions of OutputStream just provide similar code to the single character function you already wrote:
public class CustomOutputStream extends OutputStream {
private JTextArea jTextAreaOUTPUT;
public CustomOutputStream(JTextArea textArea) {
jTextAreaOUTPUT = textArea;
}
#Override
public void write(int b) throws IOException {
// redirects data to the text area
jTextAreaOUTPUT.append(String.valueOf((char) b));
// scrolls the text area to the end of data
jTextAreaOUTPUT.setCaretPosition(jTextAreaOUTPUT.getDocument().getLength());
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
// redirects data to the text area
jTextAreaOUTPUT.append(new String(b, off, len));
// scrolls the text area to the end of data
jTextAreaOUTPUT.setCaretPosition(jTextAreaOUTPUT.getDocument().getLength());
}
#Override
public void write(byte[] b) throws IOException {
write(b,0,b.length);
}
}

Related

Java - Overriding StdOut and writing Japanese to a File

I have been trying to create a class that can be set as Standard Out and that writes to a File. So far, no problem. However, when I try to write some Japanese into the output it won't show up in the files. All I get are lines of '?' characters.
This is how my OutputStream class looks like (I create an instance of it and hands that over to "System.setOut(OutputStream)" in my main method).
public class MyStdOutStream extends OutputStream {
private OutputStreamWriter out;
public MyStdOutStream(File file) throws IOException {
out = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
}
#Override
public void close() throws IOException {
out.flush();
out.close();
super.close(); //No idea if this line does anything...
}
#Override
public void write(int nr) throws IOException {
out.write(nr);
}
}
I then accept input through a JTextField (while testing, it will be a different source later), and print that both with "System.out.println(String)" and also appending it to a JTextArea. It shows up as proper Japanese in the JTextArea, but not in the File.
Does anyone know what I am doing wrong? I have tested with all available Charsets in the StandardCharsets import without success.
EDIT: It is an assignment, and I am not allowed to use anything other than the Standard Java Library (so, no imported JARs)

Invalidate Stream without Closing

This is a followup to anonymous file streams reusing descriptors
As per my previous question, I can't depend on code like this (happens to work in JDK8, for now):
RandomAccessFile r = new RandomAccessFile(...);
FileInputStream f_1 = new FileInputStream(r.getFD());
// some io, not shown
f_1 = null;
f_2 = new FileInputStream(r.getFD());
// some io, not shown
f_2 = null;
f_3 = new FileInputStream(r.getFD());
// some io, not shown
f_3 = null;
However, to prevent accidental errors and as a form of self-documentation, I would like to invalidate each file stream after I'm done using it - without closing the underlying file descriptor.
Each FileInputStream is meant to be independent, with positioning controlled by the RandomAccessFile. I share the same FileDescriptor to prevent any race conditions arising from opening the same path multiple times. When I'm done with one FileInputStream, I want to invalidate it so as to make it impossible to accidentally read from it while using the second FileInputStream (which would cause the second FileInputStream to skip data).
How can I do this?
notes:
the libraries I use require compatibiity with java.io.*
if you suggest a library (I prefer builtin java semantics if at all possible), it must be commonly available (packaged) for linux (the main target) and usable on windows (experimental target)
but, windows support isn't a absolutely required
Edit: in response to a comment, here is my workflow:
RandomAccessFile r = new RandomAccessFile(String path, "r");
int header_read;
int header_remaining = 4; // header length, initially
byte[] ba = new byte[header_remaining];
ByteBuffer bb = new ByteBuffer.allocate(header_remaining);
while ((header_read = r.read(ba, 0, header_remaining) > 0) {
header_remaining -= header_read;
bb.put(ba, 0, header_read);
}
byte[] header = bb.array();
// process header, not shown
// the RandomAccessFile above reads only a small amount, so buffering isn't required
r.seek(0);
FileInputStream f_1 = new FileInputStream(r.getFD());
Library1Result result1 = library1.Main.entry_point(f_1)
// process result1, not shown
// Library1 reads the InputStream in large chunks, so buffering isn't required
// invalidate f_1 (this question)
r.seek(0)
int read;
while ((read = r.read(byte[4096] buffer)) > 0 && library1.continue()) {
library2.process(buffer, read);
}
// the RandomAccessFile above is read in large chunks, so buffering isn't required
// in a previous edit the RandomAccessFile was used to create a FileInputStream. Obviously that's not required, so ignore
r.seek(0)
Reader r_1 = new BufferedReader(new InputStreamReader(new FileInputStream(r.getFD())));
Library3Result result3 = library3.Main.entry_point(r_2)
// process result3, not shown
// I'm not sure how Library3 uses the reader, so I'm providing buffering
// invalidate r_1 (this question) - bonus: frees the buffer
r.seek(0);
FileInputStream f_2 = new FileInputStream(r.getFD());
Library1Result result1 = library1.Main.entry_point(f_2)
// process result1 (reassigned), not shown
// Yes, I actually have to call 'library1.Main.entry_point' *again* - same comments apply as from before
// invalidate f_2 (this question)
//
// I've been told to be careful when opening multiple streams from the same
// descriptor if one is buffered. This is very vague. I assume because I only
// ever use any stream once and exclusively, this code is safe.
//
A pure Java solution might be to create a forwarding decorator that checks on each method call whether the stream is validated or not. For InputStream this decorator may look like this:
public final class CheckedInputStream extends InputStream {
final InputStream delegate;
boolean validated;
public CheckedInputStream(InputStream stream) throws FileNotFoundException {
delegate = stream;
validated = true;
}
public void invalidate() {
validated = false;
}
void checkValidated() {
if (!validated) {
throw new IllegalStateException("Stream is invalidated.");
}
}
#Override
public int read() throws IOException {
checkValidated();
return delegate.read();
}
#Override
public int read(byte b[]) throws IOException {
checkValidated();
return read(b, 0, b.length);
}
#Override
public int read(byte b[], int off, int len) throws IOException {
checkValidated();
return delegate.read(b, off, len);
}
#Override
public long skip(long n) throws IOException {
checkValidated();
return delegate.skip(n);
}
#Override
public int available() throws IOException {
checkValidated();
return delegate.available();
}
#Override
public void close() throws IOException {
checkValidated();
delegate.close();
}
#Override
public synchronized void mark(int readlimit) {
checkValidated();
delegate.mark(readlimit);
}
#Override
public synchronized void reset() throws IOException {
checkValidated();
delegate.reset();
}
#Override
public boolean markSupported() {
checkValidated();
return delegate.markSupported();
}
}
You can use it like:
CheckedInputStream f_1 = new CheckedInputStream(new FileInputStream(r.getFD()));
// some io, not shown
f_1.invalidate();
f_1.read(); // throws IllegalStateException
Under unix you could generally avoid such problems by dup'ing a file descriptor.
Since java does not not offer such a feature one option would be a native library which exposes that. jnr-posix does that for example. On the other hand jnr depends on a lot more jdk implementation properties than your original question.

Turn off date comment in properties file [duplicate]

Is it possible to force Properties not to add the date comment in front? I mean something like the first line here:
#Thu May 26 09:43:52 CEST 2011
main=pkg.ClientMain
args=myargs
I would like to get rid of it altogether. I need my config files to be diff-identical unless there is a meaningful change.
Guess not. This timestamp is printed in private method on Properties and there is no property to control that behaviour.
Only idea that comes to my mind: subclass Properties, overwrite store and copy/paste the content of the store0 method so that the date comment will not be printed.
Or - provide a custom BufferedWriter that prints all but the first line (which will fail if you add real comments, because custom comments are printed before the timestamp...)
Given the source code or Properties, no, it's not possible. BTW, since Properties is in fact a hash table and since its keys are thus not sorted, you can't rely on the properties to be always in the same order anyway.
I would use a custom algorithm to store the properties if I had this requirement. Use the source code of Properties as a starter.
Based on https://stackoverflow.com/a/6184414/242042 here is the implementation I have written that strips out the first line and sorts the keys.
public class CleanProperties extends Properties {
private static class StripFirstLineStream extends FilterOutputStream {
private boolean firstlineseen = false;
public StripFirstLineStream(final OutputStream out) {
super(out);
}
#Override
public void write(final int b) throws IOException {
if (firstlineseen) {
super.write(b);
} else if (b == '\n') {
firstlineseen = true;
}
}
}
private static final long serialVersionUID = 7567765340218227372L;
#Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<>(super.keySet()));
}
#Override
public void store(final OutputStream out, final String comments) throws IOException {
super.store(new StripFirstLineStream(out), null);
}
}
Cleaning looks like this
final Properties props = new CleanProperties();
try (final Reader inStream = Files.newBufferedReader(file, Charset.forName("ISO-8859-1"))) {
props.load(inStream);
} catch (final MalformedInputException mie) {
throw new IOException("Malformed on " + file, mie);
}
if (props.isEmpty()) {
Files.delete(file);
return;
}
try (final OutputStream os = Files.newOutputStream(file)) {
props.store(os, "");
}
if you try to modify in the give xxx.conf file it will be useful.
The write method used to skip the First line (#Thu May 26 09:43:52 CEST 2011) in the store method. The write method run till the end of the first line. after it will run normally.
public class CleanProperties extends Properties {
private static class StripFirstLineStream extends FilterOutputStream {
private boolean firstlineseen = false;
public StripFirstLineStream(final OutputStream out) {
super(out);
}
#Override
public void write(final int b) throws IOException {
if (firstlineseen) {
super.write(b);
} else if (b == '\n') {
// Used to go to next line if did use this line
// you will get the continues output from the give file
super.write('\n');
firstlineseen = true;
}
}
}
private static final long serialVersionUID = 7567765340218227372L;
#Override
public synchronized Enumeration<java.lang.Object> keys() {
return Collections.enumeration(new TreeSet<>(super.keySet()));
}
#Override
public void store(final OutputStream out, final String comments)
throws IOException {
super.store(new StripFirstLineStream(out), null);
}
}
Can you not just flag up in your application somewhere when a meaningful configuration change takes place and only write the file if that is set?
You might want to look into Commons Configuration which has a bit more flexibility when it comes to writing and reading things like properties files. In particular, it has methods which attempt to write the exact same properties file (including spacing, comments etc) as the existing properties file.
You can handle this question by following this Stack Overflow post to retain order:
Write in a standard order:
How can I write Java properties in a defined order?
Then write the properties to a string and remove the comments as needed. Finally write to a file.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
properties.store(baos,null);
String propertiesData = baos.toString(StandardCharsets.UTF_8.name());
propertiesData = propertiesData.replaceAll("^#.*(\r|\n)+",""); // remove all comments
FileUtils.writeStringToFile(fileTarget,propertiesData,StandardCharsets.UTF_8);
// you may want to validate the file is readable by reloading and doing tests to validate the expected number of keys matches
InputStream is = new FileInputStream(fileTarget);
Properties testResult = new Properties();
testResult.load(is);

Apache FTPClient for Java show FTP Commands that were run

Hello I am using Apache Commons FTP Client and I want to show the FTP Commands that the FTP Client uses so like when I use changeWorkingDirectory it should show me the FTP Command that it used like: CODEOFCOMMAND CHD .....
or when I upload a File it should show me: CODEOFCOMMAND PUT ....
Is there any possibility to do this ?
You can find it in the Apache Commons Net FAQ :
Q: How do I debug FTP applications?
A: You can add a protocol command listener; for example:
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
- Its one of the most important aspect of Object Oriented Programming to hide the implementation from the implementer (In this case the Programmer).
- And as you are using Apache's commons library for the ftp, you are permitted to use the functionality, were as the implementation is hidden.
Here for the people that also need it:
First do:
redirectSystemStreams();
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
but because I am using a JTextArea in a GUI and I need the output there I hat to redirect the output I did it by creating these Methods (Replace txtLog with your TextArea):
private void updateTextArea(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
txtLog.append(text);
}
});
}
private void redirectSystemStreams() {
OutputStream out = new OutputStream() {
#Override
public void write(int b) throws IOException {
updateTextArea(String.valueOf((char) b));
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
updateTextArea(new String(b, off, len));
}
#Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
};
System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
}

Logback+Swing in small tool

I need to hack up a small tool. It should read a couple of files and convert them. Right now that works in my IDE. For the user, I'd like to add a small UI which simply shows the log output.
Do you know of a ready-to-use Swing appender for logback? Or something which redirects System.out to a little UI with nothing more than a text field and a "Close" button?
PS: I'm not looking for Chainsaw or Jigsaw or Lilith. I want the display of the log messages in the application, please.
You need to write a custom appender class like so:
public class MyConsoleAppender extends AppenderBase<ILoggingEvent> {
private Encoder<ILoggingEvent> encoder = new EchoEncoder<ILoggingEvent>();
private ByteArrayOutputStream out = new ByteArrayOutputStream();
public MyConsoleAppender() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
setContext(lc);
start();
lc.getLogger("ROOT").addAppender(this);
}
#Override
public void start() {
try {
encoder.init(out);
} catch (IOException e) {}
super.start();
}
#Override
public void append(ILoggingEvent event) {
try {
encoder.doEncode(event);
out.flush();
String line = out.toString(); // TODO: append _line_ to your JTextPane
out.reset();
} catch (IOException e) {}
}
}
You can replace the EchoEncoder with a PatternLayoutEncoder (see CountingConsoleAppender example in the logback examples folder).
The encoder will write each event to a byte buffer, which you can then extract a string and write this to your JTextPane or JTextArea, or whatever you want.
I often rely on JTextArea#append(), as suggested in this example. Unlike most of Swing, the method happens to be thread safe.
Addendum: Console is a related example that redirects System.out and System.err to a JTextArea.
No warranty, but here's a sample that I just wrote:
/**
* A Logback appender that appends messages to a {#link JTextArea}.
* #author David Tombs
*/
public class JTextAreaAppender extends AppenderBase<ILoggingEvent>
{
private final JTextArea fTextArea;
private final PatternLayout fPatternLayout;
public JTextAreaAppender(final Context loggerContext, final JTextArea textArea)
{
fTextArea = textArea;
// Log the date, level, class name (no package), and the message.
fPatternLayout = new PatternLayout();
fPatternLayout.setPattern("%d{HH:mm:ss.SSS} %-5level - %msg");
fPatternLayout.setContext(loggerContext);
fPatternLayout.start();
// Make sure not to call any subclass methods right now.
super.setContext(loggerContext);
}
#Override
protected void append(final ILoggingEvent eventObject)
{
// Actual appending must be done from the EDT.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
final String logStr = fPatternLayout.doLayout(eventObject);
// If the text area already has lines in it, append a newline first.
if (fTextArea.getDocument().getLength() > 0)
{
fTextArea.append("\n" + logStr);
}
else
{
fTextArea.setText(logStr);
}
}
});
}
}

Categories

Resources