[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Java Alternative to InputStreamReader

Posted on 2009-02-08
25
Medium Priority
?
1,282 Views
Last Modified: 2013-11-09
I have a java application that reads input from another program written in C++.  The C++ program runs as a Windows Service and will invoke a Java application bundled as a jar.  The C++ and Java programs communiate over Standard In and Standard Out.  We have found an issue and narrowed it down to how the Java program reads data from Standard In.  The Java program will some times lock up when reading data on the readLine() method.  The Java program will work fine when it reads data from a file for input.

What is the best/correct way to read data from Standard Input from Java?  
Currently this is how we are reading data:
 
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader bf = new BufferedReader(isr);
 
br.readLine();

Open in new window

0
Comment
Question by:darkfusion
  • 10
  • 9
  • 4
  • +1
25 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 23585515
>>The Java program will some times lock up when reading data on the readLine() method.

All Java IO calls, unless you're using non-blobking IO with the java.nio package, will block until there is input to read
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23585541
0
 

Author Comment

by:darkfusion
ID: 23585723
The C++ program creates an pipe to send and receive data and returns a pipe id.  Should the Java program attach to this pipe id instead of reading from System.in ?  Is this even possible ?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Expert Comment

by:CEHJ
ID: 23585784
Not as far as  i know. Only if the pipe is working as a file can you do that. You could use TCP/IP to communicate
0
 
LVL 92

Expert Comment

by:objects
ID: 23586056
System.in is buffered and will always blocks until a line is completed. There is no way to avoid this that I am aware of.

Perhaps change how they use the pipe to ensure data is passed line by line as I outlined in your earlier question.


0
 
LVL 2

Expert Comment

by:beekeep
ID: 23586844
As objects points out, you have a problem because System.in is buffered, and then you add an extra layer of buffering with your BufferedReader.  In both cases, the bufferer will pause until the supplier generates a certain number of bytes, regardless of where the line-breaks lie.  Thus, your indefinite pauses are to be expected.  This leaves you with two problems:
 1) you need an unbuffered source of input
 2) you need to be able to do line-oriented input on that unbuffered input

For the (1) you need to bypass the standard System.in -- luckily, it looks like you should be able to use "new FileInputStream(FileDescriptor.in)".

For (2), you'll basically need to write your own "readLine()" routine.  The ones for InputStream and BufferedReader require buffering because they need to be able to handle both "\r" and "\r\n".  If you know in advance what newline convention you are going to be dealing with, you can write a straightforward, unbuffered implementation without much difficulty:
  static String readLine(final Reader in) throws IOException {
    final StringBuilder result = new StringBuilder();
    while (true) {
      final int ch = in.read();
      if (ch == -1) break;
      else if (ch == '\n') break;
      else if (ch == '\r') ;
      else result.append((char)ch);
    }
    return result.length() == 0 ? null : result.toString();
  }

Open in new window

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23588003
It's really little to do with buffering - all IO is buffered. As i mentioned, all calls to read IO block until there's input ready to read. It's true that using BufferedReader adds additional buffering, but i doubt there's much delay being added by that. You can test that easily enough by doing the below, thus using a buffer ~ 1000th of the size of the default:


BufferedReader br = new BufferedReader(new InputStreamReader(in), 8);

Open in new window

0
 
LVL 2

Expert Comment

by:beekeep
ID: 23589284
After further reading of the details of Buffered{InputStream,Reader}, I'm inclined to change my mind and agree that the problem is probably not with the Java buffering.  (I was foolishly believing that they blocked until they could fill the buffer, while instead they are happy as long as they can put *something* in the buffer.  It's never too late to learn something new.)

This being the case, I'd recommend looking at the C++ program which is writing the data.  Does it call "flush" after each line of data is complete?  I seem to recall that "autoflush" behavior in C/C++ is automatically enabled if the output device is a tty but not if it is a pipe/file.  Explicit flushes could help you be sure.
0
 
LVL 92

Expert Comment

by:objects
ID: 23589295
As I mentioned earlier, the problems not with the BufferedReader

0
 

Author Comment

by:darkfusion
ID: 23590342

Yes the pipe is flushed after each message.  

When you run the programs command line every thing works great.  The programs also work as expected on Unix.  The difference is running as a Windows Service runs under the user account SYSTEM and running as command line or Unix runs under my user account.  

Thanks -
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23590519
It's conceivable that because of the way it's been deployed as a service, it's getting process/IO starved. I suggest you put some logging debug in there to check that out
0
 

Author Comment

by:darkfusion
ID: 23591391
The Java programs is multi threaded.  When debug is turned on the point of locking is at the connection to the VMware host.

Things that work:
  - connection is made in the main java thread instead of the pool
        OR
  - connection can be made in the thread pool if Standard In is NOT used to read from the C program

Thanks -

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23591570
So not only is it running as a service, but it's running as a service in a VM?
0
 

Author Comment

by:darkfusion
ID: 23591624
No, it will make remote connections to VMware hosts to collect data. The objective of the program is to run on a normal Windows machine.

Thanks -
0
 

Author Comment

by:darkfusion
ID: 23613701
Maybe I was on the wrong track.  Could this problem be related to the SecureRandom generator?  

Thanks Everyone !
jstack.txt
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23614292
Hmm. What are the current symptoms of a problem?
0
 

Author Comment

by:darkfusion
ID: 23614611
Current symptoms of the problem

 The locking is inconsistent.  The built product has been installed on Windows XP and Windows Sever 2003 for testing.  Some will work others will hang on a lock as the attachment in a earlier post shows.

Yesterday we changed the source code for Apache Axis from:  

protected static String randomClass = "java.security.SecureRandom";

/**
     * Return the random number generator instance we should use for
     * generating session identifiers.  If there is no such generator
     * currently defined, construct and seed a new one.
     *
     * @return Random object
     */
    private static synchronized Random getRandom() {
        if (random == null) {
            try {
                Class clazz = Class.forName(randomClass);
                random = (Random) clazz.newInstance();
            } catch (Exception e) {
                random = new java.util.Random();
            }
        }
        return (random);
    }


TO

 /**
     * Return the random number generator instance we should use for
     * generating session identifiers.  If there is no such generator
     * currently defined, construct and seed a new one.
     *
     * @return Random object
     */
    private static synchronized Random getRandom() {
        if (random == null) {
            try {
                  random = new java.util.Random();
            } catch (Exception e) {
                  try {
                         Class clazz = Class.forName(randomClass);
                     random = (Random) clazz.newInstance();
                        } catch (Exception ex) {
                              throw new NullPointerException();
                        }
            }
        }
        return (random);
    }

As you can see the we forced  random to use java.util.Random() instead of java.security.SecureRandom

After the change the code was locked at another point which uses java.security.SecureRandom.

If you need any additional information or traces please let me know.

I appreciate you help on this one !!!

0
 

Author Comment

by:darkfusion
ID: 23634291
Hello,

We found a possible solution to this problem.  If we specify this property on startup of the jar every thing works as expected.

-Dcom.sun.management.jmxremote

I have used jconsole and visualvm before to monitor our applications.  I know this allows jmx connections.

 ---------------------------------------------------------------------------------------------------------------------------

1) What are the security concerns of having this property set ?

2) Could this be a permanent fix to our problem?   Meaning, would you as a customer, have any        concerns with this property set permanently and running on your network?  

Thanks
0
 
LVL 86

Accepted Solution

by:
CEHJ earned 1500 total points
ID: 23634586
It's certainly true that an open port is usually a theoretical risk. While the jmx port might not be a prime candidate for attack, it could be vulnerable in theory, so this might require work from sysadmins, even to open it in the first place
0
 

Author Closing Comment

by:darkfusion
ID: 31544312
Thanks for your help !!
0
 
LVL 92

Expert Comment

by:objects
ID: 23638442
opening up jmx is a big security risk, you're opening up the internals of your application.
let me know if you are interested in securing it, or get it working without having to open the port.

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23639786
:-)
0
 

Author Comment

by:darkfusion
ID: 23650136
Objects,

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#gdeum

From the Sun documentation the com.sun.management.jmxremote property is enabled by default for Java version 6.  

What additional steps would you take?

Thanks -
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 23650651
>>is enabled by default for Java version 6.  

Not on my system

0
 
LVL 92

Expert Comment

by:objects
ID: 23654332
> What additional steps would you take?

at a minimum password protect the port
and use ssl


0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
In this post we will learn how to make Android Gesture Tutorial and give different functionality whenever a user Touch or Scroll android screen.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
Suggested Courses
Course of the Month19 days, 14 hours left to enroll

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question