Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / June 2007

Tip: Looking for answers? Try searching our database.

Fail to redirect native library's output from console

Thread view: 
Jamaica R. - 05 May 2007 04:06 GMT
The DLL is c++ wrapping a Fortran subroutine, and called via JNI in
the Java Application. I need to read the standard output from Fortran
code, and display it to a dialog in Java Dialog. But using I/O
redirection :
System.setOut(new PrintStream(nativeDLL.getOutputStream()) ) can only
read Java's standout output, -- it doesn't work on my DLL's output...
Could you pls help me? Thanks in advance.

We can't use Process.getInputStream() since this is a DLL rather an
executable and the library is loaded without using Process, and a
class LoopedStreams is used to implement input stream.

public void run()
{

           final LoopedStreams ls = new LoopedStreams();
           PrintStream ps = new PrintStream(ls.getOutputStream());
           System.setOut(ps);
           System.setErr(ps);
              try
              {
                  LoadNativeDll.Init(m_command);
                  new LoadNativeDll(m_workingDir+"\\").start();
                                 }
              catch (Exception ex)
              {//display ex
                  return;
              }
           final BufferedReader br = new BufferedReader(new
InputStreamReader(ls.getInputStream()));
              new Thread(new Runnable()
           {
               public void run()
               {
                   try
                   {
                       String line;
                       while ((line = br.readLine())!=null)
                       {
                           //feed the line to a dialog
                           sleep(10);
                                    }
                       fireStatusEvent(this,
RegressionStatusEvent.REGRESSSION_STOP);
                   }
                   catch (Exception ex)
                   {//display ex
                            return;
                   }

               }
           }).start();

}

// now the LoopedStreams wrapper
public class LoopedStreams {
   private PipedOutputStream pipedOS =
       new PipedOutputStream();

   private boolean keepRunning = true;

   private ByteArrayOutputStream byteArrayOS =
       new ByteArrayOutputStream() {
       public void close()
       {
           keepRunning = false;
           try {
               super.close();
               pipedOS.close();
           }
           catch(IOException e) {
               // record error and deal with it
               // here simply stop it
                  System.err.println("Fail to close
ByteArrayOutputStream!");
               return;

           }
       }
   };

   private PipedInputStream pipedIS = new PipedInputStream() {
       public void close() {
           keepRunning = false;
           try    {
               super.close();
           }
           catch(IOException e) { return;    }
       }
   };

   public LoopedStreams() throws IOException {
       pipedOS.connect(pipedIS);
       startByteArrayReaderThread();
   } // LoopedStreams()

   public InputStream getInputStream() {
       return pipedIS;
   } // getInputStream()

   public OutputStream getOutputStream() {
       return byteArrayOS;
   } // getOutputStream()

   private void startByteArrayReaderThread() {
       new Thread(new Runnable() {
           public void run() {
               while(keepRunning) {
                   // check the bytes size of the stream
                   if(byteArrayOS.size() > 0) {
                       byte[] buffer = null;
                       synchronized(byteArrayOS) {
                           buffer = byteArrayOS.toByteArray();
                           byteArrayOS.reset(); // flush the buffer
                       }
                       try {
                           // send data to PipedOutputStream
                           pipedOS.write(buffer, 0, buffer.length);
                       }
                       catch(IOException e) {
                           // record error and deal with it
                           // here simply stop it
                              System.err.println("Read thread
error!");
                           return;

                       }
                   }
                   else // no data and turn the thread to sleep
                       try {
                           // check the ByteArrayOutputStream for new
data every 1s
                           Thread.sleep(1000);
                       }
                       catch(InterruptedException e) {}
                   }
            }
       }).start();
   } // startByteArrayReaderThread()
} // LoopedStreams
Gordon Beaton - 05 May 2007 07:58 GMT
> The DLL is c++ wrapping a Fortran subroutine, and called via JNI in
> the Java Application. I need to read the standard output from
[quoted text clipped - 7 lines]
> executable and the library is loaded without using Process, and a
> class LoopedStreams is used to implement input stream.

If the native code prints to stdout, then the output goes to stdout
regardless of what you do in Java. Note too that setOut() and similar
methods do not actually change the stdout of the JVM process.

You need to change the native code so that it returns its output or
posts it directly to the dialog, instead of printing it. Or put it in
a separate process so you can catch its output.

/gordon

--
Jamaica R. - 05 May 2007 08:57 GMT
Hi Gordon,

Thanks for the reply.
My native method is Fortran subroutine and wrapped into cpp library
for Java to use. Fortran code does generate large data printed to
stdout at random time.

An executable by the fortran routine was successfully redirected by
Process proc = (Runtime.getRuntime()).exec(m_commend);
BufferedReader in = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
which means Process's getInputStream() can obtain external routine's
stdout and my dedicated dialog can display them.

Now the same fortran subroutine is instead wrapped into cpp library
for Java to load with JNI technique.  With the code posted above,
despite piped output/input and redirected system.out, fortran outputs
are seen in the Eclipse (my development environment) Console panel,
not my dedicated display dialog.

So maybe it's not fault of my native code. The problem is how to get
the DLL stdout, or how to use Process with a DLL...

Best Rdgs,
Jamaica

> > The DLL is c++ wrapping a Fortran subroutine, and called via JNI in
> > the Java Application. I need to read the standard output from
[quoted text clipped - 19 lines]
>
> --
Chris Smith - 05 May 2007 14:57 GMT
> An executable by the fortran routine was successfully redirected by
> Process proc = (Runtime.getRuntime()).exec(m_commend);
> BufferedReader in = new BufferedReader(new
> InputStreamReader(proc.getInputStream()));
> which means Process's getInputStream() can obtain external routine's
> stdout and my dedicated dialog can display them.

Right.  When you execute a subprocess, Java automatically captures the
standard input, output, and error streams of that other process and
gives you access to them.

That is fundamentally different from running native code in your own
process.  That native code uses your process's standard streams.  So
you've got two options:

1. Run the Fortran code as a separate process.

2. Change something so that the Fortran code isn't really printing to
standard output.  This may be as simple as calling freopen from the C++
wrapper.

Signature

Chris Smith

rebecca.shuang@gmail.com - 06 May 2007 08:26 GMT
> So you've got two options:
>
[quoted text clipped - 6 lines]
> --
> Chris Smith

Chris Smith,

Thank you.

I am currently trying to understand the difference between thread and
process. Is it true that Process can only be invoked from an
executable command but never from a dynamic library?

By "1. Run the Fortran code as a separate process. ", do you mean I
have to change the fortran code into an ".exe"?

For "2. Change something so that the Fortran code isn't really
printing to stdout", do you mean modify fortran code to write to a
file, or return a string to C and then to Java?
If so, I don't think it is applicable because the data to print might
be thousands of lines spending tons of time, so share a string is not
preferred. And I think that concurrent write and read access for a
file is not permitted in Windows.

Great appreciated if you could you please provide further
instruction...

Regards,
Jamaica
Chris Smith - 06 May 2007 22:04 GMT
> I am currently trying to understand the difference between thread and
> process. Is it true that Process can only be invoked from an
> executable command but never from a dynamic library?

In general, it's true that the process you invoke will get its code from
an executable file -- possibly in conjunction with one or more dynamic
libraries.  You can't invoke a dynamic library as its own process.  (I'm
ignoring a certain complicated exception to this rule on the Windows
operating system; you should, too.)

If you really meant what you said -- invoked "from" -- then you're
incorrect.  It doesn't matter whether the code that actually invokes the
process is in a library or not.

> By "1. Run the Fortran code as a separate process. ", do you mean I
> have to change the fortran code into an ".exe"?

Either that or write another program to call it.  That other program
could even be written in Java; what matters is that it's a separate
process, so you can get its standard output as a stream.

> For "2. Change something so that the Fortran code isn't really
> printing to stdout", do you mean modify fortran code to write to a
> file, or return a string to C and then to Java?

It's a general strategy.  Use a file, or a string, or a named pipe, or
whatever.  The point is that you can't redirect your Fortran code's
stdout from Java, so you'll have to do something in either the C++ or
Fortran code.

Signature

Chris Smith

Jamaica R. - 06 May 2007 22:29 GMT
> <rebecca.shu...@gmail.com> wrote:
> > I am currently trying to understand the difference between thread and
[quoted text clipped - 29 lines]
> --
> Chris Smith

Thank you!
I'll try on a seperate simple Java app first...

Jamaica
Patricia Shanahan - 08 May 2007 16:05 GMT
> Hi Gordon,
>
[quoted text clipped - 9 lines]
> which means Process's getInputStream() can obtain external routine's
> stdout and my dedicated dialog can display them.

That can be implemented using pipes, without any special interception.

Telling a new job where to send its standard out is very different from
trying to change the rules for part of a running process.

> So maybe it's not fault of my native code. The problem is how to get
> the DLL stdout, or how to use Process with a DLL...

Just write a wrapper application, in any convenient language, that calls
the dll. The application's command line parameters can be used to tell
it initial parameters to pass to the dll. Your Java job can then use
ProcessBuilder and Process to control and communicate with the wrapper,
which in turn controls the dll.

Patricia
Jamaica R. - 08 May 2007 16:22 GMT
hi Patricia,

Thank you very much!
What you recommend is exactly what I finally managed to get through
today ^_^
The "wrapper" is written in an independent Java application. Then the
Process stands to help me out.

Jamaica

> Just write a wrapper application, in any convenient language, that calls
> the dll. The application's command line parameters can be used to tell
[quoted text clipped - 3 lines]
>
> Patricia
Jamaica R. - 08 May 2007 16:24 GMT
hi Patricia,

Thank you very much!
What you recommend is exactly what I finally managed to get through
today ^_^
The "wrapper" is written in an independent Java application. Then the
Process stands to help me out.

Jamaica

> Just write a wrapper application, in any convenient language, that calls
> the dll. The application's command line parameters can be used to tell
[quoted text clipped - 3 lines]
>
> Patricia
yosri - 01 Jun 2007 15:50 GMT
> hi Patricia,
>
[quoted text clipped - 13 lines]
>
> > Patricia

Hi Jamaica,

I encoutered the same problem as described this thread , can you tell
me more about the Wrapper that you used to solve the problem?

Thank you in advance.
Arne Vajhøj - 09 Jun 2007 18:48 GMT
> The DLL is c++ wrapping a Fortran subroutine, and called via JNI in
> the Java Application. I need to read the standard output from Fortran
[quoted text clipped - 3 lines]
> read Java's standout output, -- it doesn't work on my DLL's output...
> Could you pls help me? Thanks in advance.

I can understand that you have found alternative solutions, but
if you want a solution for the original problem then see:
  http://www.vajhoej.dk/arne/eksperten/jniredirect/

If the Fortran RTL are build on top of the C RTL, then
it should work for a C++ wrapper around Fortran as well.

Arne


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.