One thread keeps reading bytes received from a BufferedReader. The data comes from a SerialPort.
On the main thread, there is a JMenuItem when it's clicked the serial port is closed and the BufferedReader should stop receiving the messages.
The problem is:
If I try to close while messages are being read, the application will stuck and the serial port won't be closed until the port stops sending messages.
So basically, I should close the reader before closing the serial port. If I do this, sometimes I get a null pointer exception because I close the buffered reader while he is being read.
How can I solve this issue?
It sounds like you can fix this with a stop method in your reader class (called from the menu item's click event)
private boolean isStopped = false;
public void stop() {
isStopped = true;
}
while(bufferedReader.isReady()) {
bufferedReader.read();
if(isStopped) {
bufferedReader.close();
}
}
This way you ensure that you don't call close until all read calls have completed.
The simplest thing to do would be to create a SynchronizedReader class which would wrap your BufferedReader. But without more context, I cannot guarantee this will work, especially if you have calling code which makes multiple interdependent calls to the Reader (you would then need to ensure that all calls are made in a single synchronized(reader) block).
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
public class SynchronizedReader extends Reader {
private Reader reader;
public SynchronizedReader(Reader reader) {
super();
this.reader = reader;
}
#Override
public synchronized int read(char[] cbuf, int off, int len) throws IOException {
return reader.read(cbuf, off, len);
}
#Override
public synchronized void close() throws IOException {
reader.close();
}
#Override
public synchronized int hashCode() {
return reader.hashCode();
}
#Override
public synchronized int read(CharBuffer target) throws IOException {
return reader.read(target);
}
#Override
public synchronized int read() throws IOException {
return reader.read();
}
#Override
public synchronized int read(char[] cbuf) throws IOException {
return reader.read(cbuf);
}
#Override
public synchronized boolean equals(Object obj) {
return reader.equals(obj);
}
#Override
public synchronized long skip(long n) throws IOException {
return reader.skip(n);
}
#Override
public synchronized boolean ready() throws IOException {
return reader.ready();
}
#Override
public synchronized boolean markSupported() {
return reader.markSupported();
}
#Override
public synchronized void mark(int readAheadLimit) throws IOException {
reader.mark(readAheadLimit);
}
#Override
public synchronized void reset() throws IOException {
reader.reset();
}
#Override
public synchronized String toString() {
return reader.toString();
}
}
Related
Netty TCP Server is running at port 8000 receiving NMEA format data. It uses Marine API library to convert the gibberish to a meaningful information which needs input stream from the socket.
SentenceReader sentenceReader = new SentenceReader(socket.getInputStream());
sentenceReader.addSentenceListener(new MultiSentenceListener());
sentenceReader.start();
How can i get inputstream for netty server port being used?
SentenceReader does not have any method to accept "streamed in" data, however with subclassing, it can be made to accept the data.
The core of SentenceReader uses a DataReader for its data, normally this datareader is polled from a seperate thread SentenceReader itself, and we can modify this structure to get what we need.
First, we subclass SentenceReader with our own class, give it the proper constructor and methods we want, and remove the effect of the start and stop methods. We provide null as the file for now (and hope future versions provide a method to pass a datareader in directly)
public class NettySentenceReader extends SentenceReader {
public NettySentenceReader () {
super((InputStream)null);
}
#Override
public void start() {
}
#Override
public void stop() {
}
}
We now need to implement all functionality of the internal class DataReader inside our own Netty handler, to replicate the same behaviour
public class SentenceReaderHandler extends
SimpleChannelInboundHandler<String> {
private SentenceFactory factory;
private SentenceReader parent;
public SentenceReaderHandler (SentenceReader parent) {
this.parent = parent;
}
#Override
public void channelRegistered(ChannelHandlerContext ctx) {
if(!ctx.channel().isActive())
return;
//ActivityMonitor monitor = new ActivityMonitor(parent);
this.factory = SentenceFactory.getInstance();
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
//ActivityMonitor monitor = new ActivityMonitor(parent);
this.factory = SentenceFactory.getInstance();
}
#Override
// This method will be renamed to `messageReceived` in Netty 5.0.0
protected void channelRead0(ChannelHandlerContext ctx, String data)
throws Exception {
if (SentenceValidator.isValid(data)) {
monitor.refresh();
Sentence s = factory.createParser(data);
parent.fireSentenceEvent(s);
} else if (!SentenceValidator.isSentence(data)) {
parent.fireDataEvent(data);
}
}
#Override
public void channelInactive(ChannelHandlerContext ctx) {
//monitor.reset();
parent.fireReadingStopped();
}
#Override
public void channelUnregistered(ChannelHandlerContext ctx) {
if(!ctx.channel().isActive())
return;
//monitor.reset();
parent.fireReadingStopped();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
parent.handleException("Data read failed", e);
}
}
Finally, we need to integrate this into a Netty pipeline:
SentenceReader reader = new NettySentenceReader();
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
private static final StringDecoder DECODER = new StringDecoder();
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(DECODER);
pipeline.addLast(new SentenceReaderHandler(reader));
}
});
You can't easily as InputStream is blocking and netty is an async - non blocking API.
To abstract from a specific serialization format I thought to define the following:
public interface TransportCodec {
void write(OutputStream out, Object obj) throws IOException;
Object read(InputStream in) throws IOException;
}
A default implementation would use just Java object serialization like this:
public void write(OutputStream out, Object obj) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(obj);
oout.flush();
}
Obviously the oout.close() is missing, but for a reason: I want to be able write several objects into the same stream with independent calls to write. Looking at the source code of ObjectOutputStream (jdk 1.8), oout.close() closes the underlying stream, but also clears data structures that are part of ObjectOutputStream. But since I leave oout right to the garbage collector, I would not expect problems from not closing the stream.
Apart from the risk that a future JDK really needs the oout.close(), two questions:
What do I loose in the current JDK when not closing the ObjectOutputStream above.
First serializing into a ByteArrayOutputStream and then copying the bytes to out would allow to close oout. Are there better options?
Separate into two interfaces and make the implementation class "own" the underlying stream.
Advantages:
Underlying storage is no longer restricted to be an OutputStream / InputStream.
By making the two interfaces extend Closeable, they can now be used in a try-with-resources block.
Caller only need to carry one reference (e.g. TransportEncoder), and will no longer have to carry the stream too (e.g. OutputStream).
Interfaces
public interface TransportEncoder extends Closeable {
void write(Object obj) throws IOException;
}
public interface TransportDecoder extends Closeable {
Object read() throws IOException;
}
ObjectStream implementations
public final class ObjectStreamEncoder implements TransportEncoder {
private final ObjectOutputStream stream;
public ObjectStreamEncoder(OutputStream out) throws IOException {
this.stream = new ObjectOutputStream(out);
}
#Override
public void write(Object obj) throws IOException {
this.stream.writeObject(obj);
}
#Override
public void close() throws IOException {
this.stream.close();
}
}
public final class ObjectStreamDecoder implements TransportDecoder {
private final ObjectInputStream stream;
public ObjectStreamDecoder(InputStream in) throws IOException {
this.stream = new ObjectInputStream(in);
}
#Override
public Object read() throws IOException {
try {
return this.stream.readObject();
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
}
#Override
public void close() throws IOException {
this.stream.close();
}
}
I am trying to write a TestNgtest case for a console app for when the user inputs ESC. At which point the application should print a message and then exit. I want the TestNg to test if the message gets printed. Here's the app code:
public class Application {
public static void doSomething(Scanner scanner) {
String inputString = scanner.nextLine();
if("ESC".equals(inputString.toUpperCase())) {
System.out.println("Bye");
System.exit(0);
}
}
}
Here's the junit code:
public class ApplicationTest {
private Application app;
private ByteArrayInputStream in;
private ByteArrayOutputStream out;
#BeforeMethod
public void setUp() throws Exception {
app = new Application();
out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
}
#AfterMethod
public void tearDown() throws Exception {
System.setIn(System.in);
}
#Test
public void testESCInput() throws Exception {
in = new ByteArrayInputStream("ESC".getBytes());
System.setIn(in);
app.processInput(new Scanner(System.in));
assertTrue(out.toString().contains("Bye"));
}
}
But since the application exits with System.exit I don't even get to the assertTrue line, the TestNg just ends before that. Is there a right way to test this?
You can use a SecurityManager to reject exit attempts, then build tests around the expected exception, e.g. this works with JUnit, should be easily adapted to TestNG
public class ExitTest {
public static class RejectedExitAttempt extends SecurityException {
private int exitStatus;
public RejectedExitAttempt(int status) {
exitStatus=status;
}
public int getExitStatus() {
return exitStatus;
}
#Override
public String getMessage() {
return "attempted to exit with status "+exitStatus;
}
}
#Before
public void setUp() throws Exception {
System.setSecurityManager(new SecurityManager() {
#Override
public void checkPermission(Permission perm) {
if(perm instanceof RuntimePermission && perm.getName().startsWith("exitVM."))
throw new RejectedExitAttempt(
Integer.parseInt(perm.getName().substring("exitVM.".length())));
}
});
}
#After
public void tearDown() throws Exception {
System.setSecurityManager(null);
}
#Test(expected=RejectedExitAttempt.class)
public void test() {
System.exit(0);
}
}
This is a simple test, that is satisfied with any exit attempt. If a particular exit status is required, you have to catch the exception and verify the status.
Since this custom SecurityManager allows any other action, resetting the security manager to null is possible.
If the ByteBuffer is written partially, the position is updated and the next _channel.write call will resume from last position, yep?
compact() is not necessary?
private AsynchronousSocketChannel _channel;
private ByteBuffer _buffer;
final CompletionHandler<Integer, LogstashClientStream> _writeCompletionHandler = new CompletionHandler<Integer, LogstashClientStream>(){
#Override
public void completed(Integer sent, LogstashClientStream self) {
if( _buffer.remaining() == 0 ){
_buffer.clear();
//...
}
else {
// partial write
self.send();
}
}
#Override
public void failed(Throwable exc, LogstashClientStream self) {
//...
}
};
private void send(){
try{
_channel.write( _buffer, this, _writeCompletionHandler);
} catch(Throwable e){
//...
}
}
Yes, it will resume, and no, compact() is not necessary here. It's useful mainly in cases when you want to fill the rest of the buffer from some input stream before invoking write() again.
I am trying to write a program that redirects System.out to a JTextArea (it doesn't have to be a JTextArea), but when I call System.out.println("Test!") the output to the text area is like so:
\n
st!
\n
The code for my OutputStream:
package gui;
import java.awt.*;
import java.io.*;
import javax.swing.text.*;
public class LogOutputStream extends OutputStream
{
public void write(final int b) throws IOException
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
write0(b);
}
});
}
public void write(final byte[] b, final int off, final int len)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
write0(b, off, len);
}
});
}
public void write(final byte[] b)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
write0(b);
}
});
}
private void write0(int b)
{
Document doc = FernflowerGUI.frame.textArea.getDocument();
try
{
doc.insertString(doc.getLength(), String.valueOf((char)b), null);
}
catch(BadLocationException impossible)
{
}
}
private void write0(byte[] b, int off, int len)
{
Document doc = FernflowerGUI.frame.textArea.getDocument();
try
{
doc.insertString(doc.getLength(), new String(b, off, len), null);
}
catch(BadLocationException impossible)
{
}
}
private void write0(byte[] b)
{
write0(b, 0, b.length);
}
}
The code that creates the PrintStream:
PrintStream ps = new PrintStream(new LogOutputStream(), true);
Can anyone please tell me what on Earth is going on?
Your code isn't thread-safe, basically.
You're accepting a synchronous call accepting a byte array - and then you're using that byte array later, and assuming it will still have the same content. What if the caller to write() overwrites the data in the byte array immediately after the method returns? By the time you get to use it, you won't have the right data.
I would extract the String from the byte array in your write call, and then use that String in the call to write0.
(I'd also personally use a Writer rather than an OutputStream - fundamentally you want to deal with text data, not binary data.)