Link to home
Start Free TrialLog in
Avatar of Dcom4CIT
Dcom4CIT

asked on

Threads and .bat files

Hi all,
I am currently trying to code and java program that will be a .exe file which will run in the background of computers everytime a user logs on.  I'll will do this by putting it as a log on scripts on each machine.

My questions are, firstly I need to know how to call a .bat file from my java program. i.e. when it is a certain time I need the .bat file to be run.

Secondly I am not very familiar with threads and I need to create one so the time can be updated every minute so that the program will be running continuously while the user is logged in.

I'd appreciate any help,
Fran.

SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Why do you need to call a batch file btw?
Avatar of Dcom4CIT
Dcom4CIT

ASKER

Well what I'm trying to do is when a user books a computer if there is a user logged on that paticular computer I have to display a message and log them off.  On each computer there is software called poweroff that will do this for me. I have the commmand to do this in a . bat file so if the current time is equal to time in database for the booking I need to run this .bat file.

This is a bit long winded but I hope it explains!!
I see. All you need then is to use the first example, using the db ResultSet Date and then do

Runtime.getRuntime().exec("cmd.exe /C yourbat.bat");

when the Timer fires
following example shows how to run a bat.

http://www.objects.com.au/java/examples/util/ConsoleExec.do

command to poass to exec would be something like:

cmd /c my.bat
I had this code which does the same as yours I think but nothing happens when I run it:

      Runtime rt = Runtime.getRuntime();
      rt.exec("test.bat");

Just to be sure I just tried the code you gave me there and nothing happened.
Where should I have the batch file saved?
>>rt.exec("test.bat");

should be

rt.exec("cmd.exe /C test.bat");
you also should handle the bat output as sjown in the example I posted above.
>>Where should I have the batch file saved?

In the directory from where the app gets run
>>you also should handle the bat output

With a such a program, there may be no output ;-)
>Where should I have the batch file saved?

Specify the full path to the bat in the call to exec

> In the directory from where the app gets run

Don't make assumptions where it is being run from

> With a such a program, there may be no output ;-)

you can never be sure, even if the batch itself doesn't produce any output should still handle the output correctly instead of a lazy hack that results in hard to find errors down the track.
With this batch file it is "supposed" to dispaly a message and then log off the computer.
I executed the batch file already and it does actually do this so I dont know why it wont when I run the program???
Why btw, are you executing the program through a batch file? Why not execute it directly?
As I mentioned above, you need to read the output as shown in the example I posted above.
>Why btw, are you executing the program through a batch file? Why not execute it directly?
Its a requirement of the project but what other way could I do it?


>As I mentioned above, you need to read the output as shown in the example I posted above.
I tried to go into this page but I cant at the moment for some reason I am getting a error on the page
>>Its a requirement of the project but what other way could I do it?

something like:

rt.exec("poweroff.exe");
> Its a requirement of the project but what other way could I do it?

just replace the bat in the call with your exe

> I tried to go into this page but I cant at the moment for some reason I am getting a error on the page

Whats the error?
package au.com.objects.examples;

/*
*  Copyright (c) 2004 by Objects Pty Ltd
*/

import java.io.IOException;

import au.com.objects.io.AutoReader;

/**
*  Example demonstrating reading output from Process.exec() to console.
*
*  @author Mick Barry http://www.objects.com.au
*/

public class ConsoleExecExample implements AutoReader.Listener
{
    public void lineRead(AutoReader reader, String line)
    {
        System.out.println(line);
    }
   
    public void error(AutoReader reader, IOException ex)
    {
        ex.printStackTrace();
    }

    public void eof(AutoReader reader)
    {
    }

    public static void main(String[] args)
    {
        try
        {
            ConsoleExecExample ex = new ConsoleExecExample();
            Process p = Runtime.getRuntime().exec(args);
            AutoReader in = new AutoReader(p.getInputStream());
            in.addListener(ex);
            AutoReader err = new AutoReader(p.getErrorStream());
            err.addListener(ex);
            new Thread(in).start();
            new Thread(err).start();
            p.waitFor();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }        
    }
}


// ------------------------------------------


package au.com.objects.io;

/*
*  Copyright (c) 2001-2004 by Objects Pty Ltd
*/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;

/**
*  Reads a text stream line by line notifying registered listeners of it's progress.
*
*  @author Mick Barry http://www.objects.com.au
*/

public class AutoReader implements Runnable
{
    private BufferedReader In = null;
   
    private ArrayList Listeners = new ArrayList();
   
    /**
    *  Constructor
    *  @param in stream to read, line by line
    */
   
    public AutoReader(InputStream in)
    {
        this(new InputStreamReader(in));
    }

    /**
    *  Constructor
    *  @param in reader to read, line by line
    */

    public AutoReader(Reader in)
    {
        In = new BufferedReader(in);
    }

    /**
    *  Adds listener interested in progress of reading
    *  @param listener listener to add
    */
   
    public void addListener(Listener listener)
    {
        Listeners.add(listener);
    }

    /**
    *  Removes listener interested in progress of reading
    *  @param listener listener to remove
    */

    public void removeListener(Listener listener)
    {
        Listeners.remove(listener);
    }

    /**
    *  Handles reading from stream until eof, notify registered listeners of progress.
    */
   
    public void run()
    {
        try
        {
            String line = null;
            while (null!=(line = In.readLine()))
            {
                fireLineRead(line);
            }
        }
        catch (IOException ex)
        {
            fireError(ex);
        }
        finally
        {
            fireEOF();
        }
    }
   
    /**
    *  Interface listeners must implement
    */
   
    public interface Listener
    {
        /**
        *  Invoked after each new line is read from stream
        *  @param reader where line was read from
        *  @param line line read
        */
       
        public void lineRead(AutoReader reader, String line);
       
        /**
        *  Invoked if an I/O error occurs during reading
        *  @param reader where error occurred
        *  @param ex exception that was thrown
        */
       
        public void error(AutoReader reader, IOException ex);

        /**
        *  Invoked after EOF is reached
        *  @param reader where EOF has occurred
        */

        public void eof(AutoReader reader);
    }

    /**
    *  Notifies registered listeners that a line has been read
    */
       
    private void fireLineRead(String line)
    {
        Iterator i = Listeners.iterator();
        while (i.hasNext())
        {
            ((Listener)i.next()).lineRead(this, line);
        }
    }

    /**
    *  Notifies registered listeners that an error occurred during reading
    */

    private void fireError(IOException ex)
    {
        Iterator i = Listeners.iterator();
        while (i.hasNext())
        {
            ((Listener)i.next()).error(this, ex);
        }
    }

    /**
    *  Notifies registered listeners that EOF has been reached
    */

    private void fireEOF()
    {
        Iterator i = Listeners.iterator();
        while (i.hasNext())
        {
            ((Listener)i.next()).eof(this);
        }
    }
   
}
No unfortunately that wont work....
This is what I have in my batch file
D:\pwroff30\poweroff logoff -warn -warntime 10 -msg "You will be logged off in 10 seconds"
you can include args in your exec() call thats fine.
Using a bat file is better from a maintenance perspective though.
>>just replace the bat in the call with your exe

Already mentioned

You can just do

String[] args = { "D:/pwroff30/poweroff",  "logoff", "-warn", "-warntime 10", "-msg", "You will be logged off in 10 seconds" };
Runtime.getRuntime().exec(args);
> Already mentioned

Then so is what you just posted :-D
And also that its probably not a good wat to go anyway.
Okay I think Im going to try stick with having the batch file.

Why do you think this piece of code isnt working?
      Runtime rt = Runtime.getRuntime();
      rt.exec("cmd.exe /C test.bat");
 And what else should I include?
as i've mentioned above
1. specify the absolute location of the bat
2. handle the bat file output using the code i posted above
>as i've mentioned above
>1. specify the absolute location of the bat
   Okay Ive that done now

>2. handle the bat file output using the code i posted above
  Im fairly new to this so the code you posted is kinda confusing to me, and Im under bit of pressure to get this sorted.
you can test with the above code using:

java au.com.objects.examples.ConsoleExecExample "cmd.exe /C c:\\mybatfiles\\test.bat"
Try this code too - it's only two lines:

String[] args = { "D:/pwroff30/poweroff",  "logoff", "-warn", "-warntime 10", "-msg", "You will be logged off in 10 seconds" };
Runtime.getRuntime().exec(args);

while using a batch file is a good idea in some ways, they can also cause problems since different platforms use different interpreters
> they can also cause problems since different platforms use different interpreters

And which platforms exactly are those that won't run a batch file.


String[] args = { "D:/pwroff30/poweroff",  "logoff", "-warn", "-warntime 10", "-msg", "You will be logged off in 10 seconds" };
Runtime.getRuntime().exec(args);

I tried that but got an error.
I dont have much time to test it now cause the labs are closing now but I'll be back early tomorrow morning! :-)
>>And which platforms exactly are those that won't run a batch file.

That's *not* what i said. Read my comment again
>>I tried that but got an error.

What error is that?
> I tried that but got an error.

I wouldn't worry about it, using a bat is more maintainable solution
You need to catch exceptions when using Runtime.exec:


try {
      String[] args = { "D:/pwroff30/poweroff",  "logoff", "-warn", "-warntime 10", "-msg", "You will be logged off in 10 seconds" };
      Runtime.getRuntime().exec(args);
}
catch(Exception e) {
      e.printStackTrace();
}
> You need to catch exceptions when using Runtime.exec:

I've already posted some example code, no need for repetition.
Yea I am doing a catch... This is my code:  

 try {
      Runtime rt = Runtime.getRuntime();
      rt.exec("cmd.exe /C c:\\PcBooking\bookpc\test.bat");

      }
    catch (Exception e) {
      e.printStackTrace();
      System.out.println("Problem calling the .bat file "+ e.getMessage());
      }

Im confused as to what else I need to include
Another question I have is in this .exe file that I'll have running continuously there will be an SQL statement.... I just want to make sure that it wont cause complications when I try to access the  same database from my web page.  Im using Access database.
>>that I'll have running continuously

I'm confused - i thought you wanted Java to start the program at a specific time?
I'll need the java program to be running continously because it is a booking system and the time from the system needs to be updated continously.  Then for example if user books computer for 2pm the java program will have an if satement that will run the .bat file at that time if the time in database is equal to system time.
I got it sorted... This is what I did

    Runtime load = Runtime.getRuntime();
    load.exec("c:\\test.bat");
>>I'll need the java program to be running continously

Yes, i know that - i was just a little puzzled since you implied the exe would run continuously:

>>Another question I have is in this .exe file that I'll have running continuously

This:

>>load.exec("c:\\test.bat");

should really be


load.exec("cmd /C c:\\test.bat");
>>load.exec("cmd /C c:\\test.bat");

Does it have to be that?
Why I tried that in my code it didnt work but this did
load.exec("c:\\test.bat");
If it works then use it. Does this work btw?

load.exec("command c:\\test.bat");



Tried that but I get this error
java.io.IOException: CreateProcess: command c:\test.bat error=2
What happened when you tried the code to run the executable directly?
>What happened when you tried the code to run the executable directly?
Nothing it just froze.

Remember I was asking in question earlier about having the program running continously and got piece of code for scheduler.  I was just wondering what is the difference between this and threads???
To be honest I dont really know much about threads!!!... but I was advised to use one as it'd be the best possible solution when I need to have it running continuously???
I'm still confused :-)

If it's running continuously, then why

>>i.e. when it is a certain time I need the .bat file to be run.

?
ok....
Its not running continuously yet... I was advised to do this by having a thread???
At the moment when I run the program and it checks the times in database with current time but I'll need it to do this continuously while a user is logged on... the whole time checking the database for a booking and then if there is a booking the user will have to be locked off and this will be done by call the batch file.
Does that explain it?
So are you intending to have one program monitoring all users or one for each?
Ut's a pc booking system.
On all the copmuters I'll have this script running which will log a user off if the computer is booked fro a certain time.  And then I have a web site that users can use to book the computers.
What OS are you using? Will it vary (different versions included)?
I'll assume you're not running Win98 or even less. The files will come in separate comments

a. save the first file as NetCafeWatcher.java
b. save the second file as RunAsync.java in the same directory as the first
c. save the third file as C:\logoff.bat (this merely opens notepad)
d. compile the first file
e. run the app

Where i've put 'Override this' as comments, those are the methods you need to change. You should make a db query using a PreparedStatement, probably using the ip address of the machine as a key
import java.util.Timer;
import java.util.Date;
import java.util.TimerTask;

public class NetCafeWatcher extends TimerTask {
      private Query fakeQuery;
      private Timer timer;
      private long timeout;


      public void run() {
            RunAsync.main(new String[] { "cmd.exe", "/C", getBatchFilePath()});
      }

      // Override this
      public String getBatchFilePath() {
            return "c:/logoff.bat";
      }

      public void init() {
            fakeQuery = new Query();
            timeout = fakeQuery.getTimeout();
            Timer timer = new Timer();
            timer.schedule(this, new Date(fakeQuery.getTimeout()));
      }


      public static void main(String[] args) {
            NetCafeWatcher ncw = new NetCafeWatcher();
            ncw.init();
      }



}

class Query {
      //String exampleQuery = "SELECT timeout FROM users WHERE ip_address = ?";
      // Use a PreparedStatement for this

      // Override this
      public long getTimeout() {
            return System.currentTimeMillis() + 10000;
      }

}
import java.io.*;

/**
 *  Description of the Class
 *
 * @author     CEHJ
 * @created    23 February 2004
 */
public class RunAsync {

  /**
   *  Description of the Method
   *
   * @param  args  Description of the Parameter
   */
  public static void main(String args[]) {

    try {

      if (args.length < 1) {
        System.out.println("Usage: java RunAsync <command string>");
        System.exit(-1);
      }
      Process pro = null;
      if (args.length > 1) {
        pro = Runtime.getRuntime().exec(args);
      }
      else {
        pro = Runtime.getRuntime().exec(args[0]);
      }
      InputStream error = pro.getErrorStream();
      InputStream output = pro.getInputStream();
      Thread err = new Thread(new OutErrReader(error));
      Thread out = new Thread(new OutErrReader(output));
      out.start();
      err.start();
      pro.waitFor();
    }
    catch (java.io.IOException e) {
      e.printStackTrace();
    }
    catch (java.lang.InterruptedException e) {
      e.printStackTrace();
    }

  }


  /**
   *  Description of the Class
   *
   * @author     CEHJ
   * @created    23 February 2004
   */
  static class OutErrReader implements Runnable {
    InputStream is;


    /**
     *Constructor for the OutErrReader object
     *
     * @param  is  Description of the Parameter
     */
    public OutErrReader(InputStream is) {
      this.is = is;
    }


    /**
     *  Main processing method for the OutErrReader object
     */
    public void run() {
      try {
        BufferedReader in = new BufferedReader(new InputStreamReader(is));
        String temp = null;
        while ((temp = in.readLine()) != null) {
          System.out.println(temp);
        }
        is.close();
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

@echo off
call notepad.exe
That code does the same as what has already been posted.
Try running you bat thru the application I posted earlier, it should fix your problem.

Yea i have solved the problem with my bat file it is now calling it properly.... Thanks! :-)
My next problem is I am using a scheduler to have the program running.
I have the query to the database inside a while loop and then a condition that will call the batch file.
My problem now is that I need to break out of the while loop and the the scheduler???
>>I have the query to the database inside a while loop

Why is that?
> My problem now is that I need to break out of the while loop and the the scheduler???

shouldn't be a problem, typically you'd have a flag in your while loop condition which you'd switch when you want it to exit
>shouldn't be a problem, typically you'd have a flag in your while loop condition which you'd switch when you want it to exit

Oh yea stupid question... Should have thought of that. I was half asleep last night!!!

Which do you think is a better option to use, a scheduler which I have at the moment or should i look into using threads.  What would the difference be... does either option have any option have advantages over the other?
A Timer *is* a thread, but i'm still unclear as to why you need a while loop? Have you run the code i posted (a large proportion of what you need)?
Just to make it clearer.  This is my code...

package bookpc;

import java.sql.*;
import java.util.Date;
import java.text.*;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import java.lang.System;   //need this for runtime
import java.lang.Runtime;
import java.io.IOException;

import java.net.InetAddress;


public class BookingApplication
{

  public BookingApplication() {

  }

  public static void main(String[] args) throws IOException {
        int delay = 5000;   // delay for 5 sec.
        int period =60000;  // repeat every Minute.
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
                public void run() {
 
                    //String username = System.getProperty("user.name");
              try
                 {
                   Date currentDate = new Date();
                   SimpleDateFormat myDateFormat = new SimpleDateFormat();
                   myDateFormat.applyPattern("dd/MM/yyyy");
                   String date = (myDateFormat.format(currentDate));
               
                   SimpleDateFormat myTimeFormat = new SimpleDateFormat();
                   myTimeFormat.applyPattern("HH:mm");
                   String time = (myTimeFormat.format(currentDate));
                   

                   java.net.InetAddress localMachine = java.net.InetAddress.getLocalHost();
                   String pc = localMachine.getHostName();

                   System.out.print("pc is " + pc);

                   ConnectToDatabase dbConnection = new ConnectToDatabase();
                   String query = "SELECT * FROM PcBookings WHERE PCName = '" + pc + "'";
                   ResultSet bookingsRS;

                   bookingsRS = dbConnection.queryDatabaseWithReturn(query);
                   boolean stop = false;
                   while (bookingsRS.next()&& stop!=true)
                   {

                     String DBDate;
                     DBDate = bookingsRS.getString("SDate");

                     if (DBDate.equals(date)) {
                       String DBTime;
                       DBTime = bookingsRS.getString("STime");
                            if (DBTime.equals(time))

                       {

                         try {
                           Runtime load = Runtime.getRuntime();
                          load.exec("c:\\logoff.bat");
                         stop = true;   //Does not break out keeps checking after every other minute
                       }

                         catch (Exception e) {

                           e.printStackTrace();
                           System.out.println("Problem calling the .bat file " +
                                              e.getMessage());
                         }

                       }

                       else {
                         System.out.println("The times are not equal");
                       }

                     }
                     else {
                       System.out.println("These dates are not equal");
                     }

                   }
                 }


                 catch (Exception sqlExc)
                 {
                   System.out.println("Error executing the query: " + sqlExc.getMessage());
                 }

                 new BookingApplication();

               }
            }, delay, period);//finish task here

  }
}

The problem Im havung with that cide is when I call the .bat file I just want to program to finish. I tried the boolean but did not work... Every minute after it still keep checking



I'm wondering why you're using a repeating Timer - surely all you need to do is look up the stop time once in the db (as per my code)?
>I'm wondering why you're using a repeating Timer - surely all you need to do is look up the stop time once in the db (as per my code)?

I dont have a stop time in the database
You should put a stop time in the db, then you can vary it as necessary. In order to stop the app cleanly, make the following change to my code (a similar approach can be taken in yours):


public void run() {
      timer.cancel();
      RunAsync.main(new String[] { "cmd.exe", "/C", getBatchFilePath()});
}


public void init() {
      fakeQuery = new Query();
      timeout = fakeQuery.getTimeout();
      timer = new Timer();
      timer.schedule(this, new Date(fakeQuery.getTimeout()));
}
> I'm wondering why you're using a repeating Timer

well you suggested it
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
If you just want the program to exit then you could also simply call

System.exit(0);
And if you wanted to wait for the process to complete use the waitFor() method

      Process p = load.exec("c:\\logoff.bat");
      // uncomment next two lines to read stdout
      // AutoReader in = new AutoReader(p.getInputStream());
      // new Thread(in).start();
      // uncomment next two lines to read stderr
      // AutoReader err = new AutoReader(p.getErrorStream());
      // new Thread(err).start();
      p.waitFor();

>>well you suggested it

Don't be silly. That was a general suggestion made for timers before i was told there is a database
OK, just to clarify then, the simplest option is for the java app to read from the database at startup to find out how long there is before time out. There are various option to make this more sophisticated, but it's probably just as well to get that running at first. A repeating timer is not required there
>   stop = true;   //Does not break out keeps checking after every other minute

you also need to cancel your timer

timer.cancel();

Yea this worked to solve my problem of breaking out of timer.

Thanks for yer help!!!!!!!!!
:-)