A usable solution for console output capturing - java - java

I am making a program that will have the ability to run the java compiler and jvm right from within it (Don't ask me why I am reinventing the wheel, if your reply does not help, save it, I am already quite frustrated spending hours on solutions that do not work!). So far I have managed it to track whenever I input something in my textField that starts with java so that it will actually wrap up the text and give it a run like so:
if(String.valueOf(object).startsWith("java")){
try{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(String.valueOf(object));
}
catch(Exception e){gsc.mainWindow.printf("error");}
Consider gsc.mainWindow.printf(...); my output to a JTextArea within a JFrame.
What I have managed now is to run the commands, but anything fails I shall be able to print it directly to my output. I know this has been answered a ton of times before, read about 10 ways to do this, but none of them worked or was understandable to the point that I could run it. I need the code to be simple enough as this will have to be outputting what the proccess will be writing in the default system's Console (cmd,terminal) and then stop (I thought that this can be a method call alltogether). I am quite bad with this kind of stuff, even a multithread solution could fit my needs, nothing too professional really, I just need it to work. Any information you need, ask away!
Thanks in advance! :)

I don't know you if you want to read this, but you know, in the Java world, you should always look for a solution before implementing your own. And the solution for common problems, most of the time, comes from Apache Commons or other Apache projects. Saying that everything but your solution doesn't work or is too complicated to you will only cost you time and money (and your job, eventually).
Apache Commons Exec is what you need to solve your problem faster and easier.
---- Edit ----
Here is some code of how to capture the output of the child process. There's a class just for it, the PumpStreamHandler:
DefaultExecutor exec = new DefaultExecutor();
PumpStreamHandler streamHandler = new PumpStreamHandler();
exec.setStreamHandler(streamHandler);
CommandLine commandline = CommandLine.parse(command); //where command is your command line
exec.execute(commandline);
---- Edit 2 ----
Here is the copy-paste solution you want to capture the message using an OutputStream:
public abstract class LogOutputStream extends OutputStream {
protected static final String LINE_SEPERATOR = System.getProperty("line.separator");
public static final int DEFAULT_BUFFER_LENGTH = 2048;
protected boolean hasBeenClosed = false;
protected byte[] buf;
protected int count;
private int bufLength;
public LogOutputStream() {
bufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[DEFAULT_BUFFER_LENGTH];
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
if (b == 0) {
return;
}
if (count == bufLength) {
final int newBufLength = bufLength + DEFAULT_BUFFER_LENGTH;
final byte[] newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, bufLength);
buf = newBuf;
bufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count == 0) {
return;
}
if (count == LINE_SEPERATOR.length()) {
if (((char) buf[0]) == LINE_SEPERATOR.charAt(0)
&& ((count == 1) ||
((count == 2) && ((char) buf[1]) == LINE_SEPERATOR.charAt(1)))) {
reset();
return;
}
}
final byte[] theBytes = new byte[count];
System.arraycopy(buf, 0, theBytes, 0, count);
log(new String(theBytes));
reset();
}
private void reset() {
count = 0;
}
public abstract void log(String message);
}
Then just create a subclass of it, implement the public void log(String message) with the code that updates the UI, and it's done.

Related

Running a message loop in a thread

I want to run a low level keyboard hook using JNA. I've adapted an example found within JNA contrib folder
private static HHOOK keyHook;
private static LowLevelKeyboardProc keyCallback;
public static void main(String[] args) {
final User32 U32 = User32.INSTANCE;
final Kernel32 K32 = Kernel32.INSTANCE;
HMODULE module = K32.GetModuleHandle(null);
keyCallback = (int code, WPARAM wParam, KBDLLHOOKSTRUCT info) -> {
if (code >= 0) {
System.err.println("Key=" + info.vkCode);
if (info.vkCode == 81) {
U32.PostQuitMessage(0);
}
}
long peer = Pointer.nativeValue(info.getPointer());
return U32.CallNextHookEx(keyHook, code, wParam, new LPARAM(peer));
};
keyHook = U32.SetWindowsHookEx(WH_KEYBOARD_LL, keyCallback, module, 0);
System.out.println("Hook installed, type anywhere, 'q' to quit");
MSG msg = new MSG();
while (U32.GetMessage(msg, null, 0, 0) > 0) {
U32.TranslateMessage(msg);
U32.DispatchMessage(msg);
}
U32.UnhookWindowsHookEx(keyHook);
}
This is working as expected. Now however, I want to run the message loop in a thread to avoid blocking my application. A naive approach would be
Executor thread = Executors.newSingleThreadExecutor();
thread.execute(() -> {
int result;
MSG msg = new MSG();
while ((result = U32.GetMessage(msg, null, 0, 0)) > 0) {
U32.TranslateMessage(msg);
U32.DispatchMessage(msg);
}
U32.UnhookWindowsHookEx(keyHook);
});
Sadly this is not working. The callback is no longer invoked and keyboard inputs on the system start lagging massively. How can I thread my message loop correctly? I suppose I need to find the thread id and pass it to SetWindowsHookEx instead of 0, but how to obtain that id?
Edit: I've tried a different approach by encapsulating the whole hook registering and message loop in one thread. The callback now works correctly, but PostQuitMessage does not seem to post the message to the correct queue and the thread cannot be stopped. PostThreadMessage(0, User32.WM_QUIT, null, null) does not work either in that case.
I've found the solution is actually already provided by the JNA Platform in User32Util.MessageLoopThread

Run C program with interactive IO using ProcessBuilder

I’m developing an IDE kind of software for C/C++ using java (although there are lots of available, but I want my own) that can compile and execute C or C++ program. So I tried a simple program to compile and execute the C program in java using Process and ProcessBuilder.
Here is my simple java program which compiles and execute C program:
public class RunProgram {
public static void main(String[] args) throws Exception {
new ProcessBuilder("gcc", "-o", "first", "first.c").start().waitFor(); //To Compile the source file using gcc and wait for compilation
/*
Although I've to handle error-stream but
for now, my assumption is that there is no error
in program.
*/
ProcessBuilder run = new ProcessBuilder("./first");
execute.redirectErrorStream(true);
Process runProcess = run.start();
StreamReader sr = new StreamReader(runProcess.getInputStream());
new Thread(sr).start(); //A new thread to handle output of program .
//rest of coding to provide input using OutputStream of 'runProcess' and to close the stream.
}
}
class StreamReader implements Runnable {
private InputStream reader;
public StreamReader(InputStream inStream) {
reader = inStream;
}
#Override
public void run() {
byte[] buf = new byte[1024];
int size = 0;
try {
while ((size = reader.read(buf)) != -1) {
System.out.println(new String(buf));
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here is my first.c program.
#include<stdio.h>
int main() {
int a;
int k;
printf("input a: ");
scanf("%d", &a);
for(k = 0; k < a; k++)
printf("k = %d\n", k);
return 0;
}
I want to create interactive IO console just like most of the IDEs or command terminals(Terminal in Linux bases OS and command prompt in Windows based OS). For above example: firstly, it should print “Input a: “and then wait for input to be provided and then rest of program. But It won’t work as I thought, as it doesn’t print the result of printf statement appeared before scanf until I provide input possibly using OutputStream.
I googled for my problem and visited many links but didn't get solution. Mean while, I found this link which suggest to append fflush after every printf statement or use setbuf or setvbuf methods (from some other sub-links) to clear the buffer. But a new person (who is going to learn C) might not be aware of fflush or these functions and he/she will never use it, as it doesn’t require in other IDEs or not even on terminals.
How can I solve this problem and can build integrated console for my IDE
Here is a glimpse of what I want:
From the comments above, think adding a little bit of explanation of how buffering for I/O streams works makes sense here.
What happens behind the scenes when calling printf(3) and the like is that the data is written to a buffer until the buffer fills up or some trigger happens.
The content of the buffer is then copied from the buffer to the actual output device/another output buffer ...
The trigger is usually encountering a line end (\n under Linux/Unix).
Thus a crude version of this buffering is:
struct buffered_file_t {
char* buffer;
size_t capacity;
size_t current_char;
FILE* file;
};
void flush_buffered(struct buffered_file_t* file) {
assert(0 != file);
assert(0 != file->buffer);
fwrite(file->buffer, file->current_char, 1, file->file);
file->current_char = 0;
}
void print(struct buffered_file_t* file, const char* str) {
assert(0 != file);
assert(0 != file->buffer);
assert(0 != str);
for(size_t i = 0; 0 != str[i]; ++i) {
if(file->current_char >= file->capacity - 1) flush_buffered(file);
file->buffer[file->current_char++] = str[i];
if('\n' == str[i]) flush_buffered(file);
}
}
Now, if you invoke print like
const size_t BUFSIZE = 100;
struct buffered_file_t stdout_buffered = {
.buffer = calloc(1, BUFSIZE),
.capacity = BUFSIZE,
.current_char = 0,
.file= stdout,
};
print(&stdout_buffered, "Naglfar\n");
print(&stdout_buffered, "Surthur");
You won't see Surthur appear onstdout ever.
In order to have it written from the buffer to stdout, you have to either
call flush_buffered explicitly
Disable buffering by reducing the buffer size (buffered_file.capacity = 1 in the example above)
In your case, you cannot invoke fflush(3) explicitly (that's what you stated as requirement). thus the only means left is disabling buffering.
How to do this is OS dependent, IMHO.
For Linux, look at stdbuf(1) from the Coreutils package to find out how to diable buffering for certain streams of foreign processes.
Under GNU/Linux, for switching off buffering for the standard I/O streams, you could use stdbuf(1)like so:
....
ProcessBuilder run = new ProcessBuilder("stdbuf", "-o0", "./first");
....
Add -e0 and -i0 options if you want to turn off buffering for stderr and stdin as well.
Of course, it would be nicer if you would not have to rely upon external tools but could do switching off buffering in your own code - simplest thing is to have a look at the source of stdbuf, but I guess it would end up in you having to use the JNI, and then, I guess, I would just stick to stdbuf ...

How would I receive input from console without blocking?

Note: I understand that the console is for debugging and games should use GUI. This is for testing/experience
I'm writing a game that runs at 60fps. Every update, I check to see if the user has entered a String command. If so, it gets passed through, but if not, null is paas through, and the null is ignored.
Scanner is out of the question, since hasNext(), the method used to see if there is data to read, can potentially block and causes problems.
I've tried using BufferedReader.ready(). Not only did I have problems (never returned true), but I've read that it's not recommended for a few reasons.
BufferedReader.available() always returned 0, which in the documentation, it state's that InputStream.available() will always return 0 unless overriden. Here is my attempt:
class Game {
public static void main(String[] args) {
InputReader reader = new InputReader(System.in);
int timePerLoop = 1000/30;
Game game = new Game();
while(true) {
long start = System.nanoTime();
game.update(reader.next());
long end = System.nanoTime();
long sleepTime = timePerLoop + ((start - end) / 10000000);
if(sleepTime > 0)
try {
Thread.sleep(sleepTime);
}catch(InterruptedException e) {
e.printStackTrace();
}
else
Thread.yield();
}
}
public void update(String command) {
if(commands != null) {
//handle command
}
//update game
}
}
InputReader.java
public class InputReader {
private InputStream in;
public InputReader(InputStream stream) {
in = stream;
}
public String next() {
String input = null;
try {
while(in.available > 0) {
if(input == null)
input = "";
input += (char) in.read();
}
}catch(IOException e) {
e.printStackTrace();
}
return input;
}
}
InputStream by itself has the same problem as above. I'm not completely sure what type the object stored in System.in, but using available() yields the same results.
I've tried using the reader() from System.console(), but console() returns null. I've read into the subject, and I am not confused why. This is not the way to do it.
The goal is to check the stream to see if it contains data to read, so I can read the data knowing it won't block.
I do not want to use a separate Thread to handle user input, so please don't recommend or ask why.
The input has to be from the console. No new sockets are to be created in the process. I have read a few topics about it, but none of them clearly states a solution. Is this possible?
As you have said yourself, a custom GUI or an additional thread is the correct way to do this. However in absence of that, have you tried using readLine() for example: String inputR = System.console().readLine();
Some alterations to main():
Replace: InputReader reader = new InputReader(System.in); with:
Console c = System.console();
Replace: game.update(reader.next());
with: game.update(c.readLine());
Edit: This thread could also be helpful: Java: How to get input from System.console()

Reading data occasionally from a socket without closing it

Info
I'm trying to find a way to read blocks of data from an incoming socket stream at a set interval, but ignoring the rest of the data and not closing the connection between reads. I was wondering if anyone had some advice?
The reason I ask is I have been given a network connected analogue to digital converter (ADC) and I want to write a simple oscilloscope application.
Basically once I connect to the ADC and send a few initialisation commands it then takes a few minutes to stabilise, at which point it starts throwing out measurements in a byte stream.
I want to read 1MB of data every few seconds and discard the rest, if I don't discard the rest the ADC will buffer 512kB of readings then pause so any subsequent reads will be of old data. If I close the connection between reads the ADC then takes a while before it sends data again.
Problem
I wrote a simple Python script as a test, in this I used a continuously running thread which would read bytes to an unused buffer, if a flag was set, which seems to work fine.
When I tried this on Android I ran into problems as it seems that only some of the data is being discarded, the ADC still pauses if the update interval is too long.
Where have I made the mistake(s)? My first guess is synchronisation as I'm not sure its working as intended (see the ThreadBucket class). I'll have to admit spending many hours on playing with this, trying different sync permutations, buffer sizes, BufferedInputStream and NIO, but with no luck.
Any input on this would be appreciated, I'm not sure if using a thread like this is the right way to go in Java.
Code
The Reader class sets up the thread, connects to the ADC, reads data on request and in between activates the bit bucket thread (I've omitted the initialisation and closing for clarity).
class Reader {
private static final int READ_SIZE = 1024 * 1024;
private String mServer;
private int mPort;
private Socket mSocket;
private InputStream mIn;
private ThreadBucket mThreadBucket;
private byte[] mData = new byte[1];
private final byte[] mBuffer = new byte[READ_SIZE];
Reader(String server, int port) {
mServer = server;
mPort = port;
}
void setup() throws IOException {
mSocket = new Socket(mServer, mPort);
mIn = mSocket.getInputStream();
mThreadBucket = new ThreadBucket(mIn);
mThreadBucket.start();
// Omitted: Send a few init commands a look at the response
// Start discarding data
mThreadBucket.bucket(true);
}
private int readRaw(int samples) throws IOException {
int current = 0;
// Probably fixed size but may change
if (mData.length != samples)
mData = new byte[samples];
// Stop discarding data
mThreadBucket.bucket(false);
// Read in number of samples to mData
while (current < samples) {
int len = mIn.read(mBuffer);
if (current > samples)
current = samples;
if (current + len > samples)
len = samples - current;
System.arraycopy(mBuffer, 0, mData, current, len);
current += mBuffer.length;
}
// Discard data again until the next read
mThreadBucket.bucket(true);
return current;
}
}
The ThreadBucket class runs continuously, on slurping data to the bit bucket if mBucket is true.
The synchronisation is meant to stop either thread from reading data whilst the other one is.
public class ThreadBucket extends Thread {
private static final int BUFFER_SIZE = 1024;
private final InputStream mIn;
private Boolean mBucket = false;
private boolean mCancel = false;
public ThreadBucket(final InputStream in) throws IOException {
mIn = in;
}
#Override
public void run() {
while (!mCancel && !Thread.currentThread().isInterrupted()) {
synchronized (this) {
if (mBucket)
try {
mIn.skip(BUFFER_SIZE);
} catch (final IOException e) {
break;
}
}
}
}
public synchronized void bucket(final boolean on) {
mBucket = on;
}
public void cancel() {
mCancel = true;
}
}
Thank you.
You need to read continuously, period, as fast as you can code it, and then manage what you do with the data separately. Don't mix the two up.

Java writing bytes to serial port USB

I have a code below that I am sending to a serial USB port...
it was working, now its not!
the akber() function dies if the wrong string is sent...
if I send akber("1.0.0.0.1.5") - it works perfectly,
if I send akber("23.0.128.0.0.5") - it does not work...
See code below
public static byte[] akber(final String input) {
StringTokenizer tokens = new StringTokenizer(input, ".");
int numberOfArrays = tokens.countTokens();
byte[][] byteArrays;
byteArrays = new byte[numberOfArrays][4];
int i = 0;
int space = 0;
while (tokens.hasMoreTokens()) {
int x = Integer.valueOf(tokens.nextToken());
if (x<256) { space++; } else { space+=2; }
byteArrays[i] = BigInteger.valueOf(x).toByteArray();
i++;
}
final byte[] output = new byte[space];
copySmallArraysToBigArray(byteArrays, output);
return output;
}
public static void copySmallArraysToBigArray(final byte[][] smallArrays, final byte[] bigArray) {
int currentOffset = 0;
for (final byte[] currentArray : smallArrays) {
System.arraycopy(currentArray, 0, bigArray, currentOffset, currentArray.length);
currentOffset += currentArray.length;
}
}
called from function:
serialPort.writeBytes(akber(data));
I would need it to work with any combination of numbers in the "data" string, so it converts them to the right type of bytes and writes to port... its not my code, and I don't quite understand it, but still need to fix it :-)
Change this line:
if (x<256) { space++; } else { space+=2; }
to
if (x<128) { space++; } else { space+=2; }
I ran your code, originally it throws an IndexOutOfBoundsException for
akber("1.0.128.0.0.5");
so check your code that it is not consuming exceptions somewhere, e.g.
try {
exceptionThrowingMethod();
}
catch(Exception e) {
}
If the exceptionThrowingMethod throws an exception the code will continue as if the exception was not thrown (but the exceptionThrowingMethod didn't execute succesfully!)
Actually although the above allowed the code to continue working, it did not solve the problem as byte values from the function above 128 were the negative equivalent or something, and sent the wrong values, so the USB hardware was receiving the incorrect characters and not working... by looking at other posts about "Java 128 bytes" on stackoverflow, worked out its something to with byte code above 128 being the same as its negative equivalent, so solved it with trial and error, very annoying - but changed that line to:
if (x<128) { space++; } else { space+=2;
int x2 = (x-128)*2;
x=x-(x*2);
if (x<-128) { x=x+x2; }
}
which seemed to work.
So happy days, till I find another issue with it! Might be a simple solution for people looking to convert values above 127 to bytes, than more standard Java solution I saw and didnt really understand, as am more used to scripting.
Thanks.

Categories