4

I have one runnable JAR file that is scheduled to run independently using Timer .

The same JAR is executed through web application(developed in spring MVC).

I have to restrict the execution of JAR in a situation when if jar is executing through timer then at that time it is not allowed to execute through web app.

Note: [I have used processbuilder to execute the JAR.]

Avyaan
  • 1,285
  • 6
  • 20
  • 47
  • With timer you mean a OS specific cron job? – mika Nov 19 '16 at 12:20
  • @mika yes.it is scheduled to execute in time intervals. – Avyaan Nov 19 '16 at 12:31
  • 1
    The best solution would probably be to make your application use a OS tool that can return a list of all running processes. If you find the application's name in the list, it is already running. You could also work with a semaphore approach, in which you write e.g. the PID of your application into a file and (again) use a OS tool to lookup if the PID is currently in use... but this probably more error prone and actually even more coding to do. Fyi, have a look here: http://stackoverflow.com/questions/2318220/how-to-detect-via-java-whether-a-particular-process-is-running-under-windows – mika Nov 19 '16 at 12:40
  • @mika but that solution is limited to the scope of the jar and the webapp running in the same machine. if you still would want to do this in a clustered environment, you would want to write the file to a [NFS](https://en.wikipedia.org/wiki/Network_File_System) location. – Sourabh Nov 28 '16 at 22:03

5 Answers5

1

I think you are developing licenseable jar . In my humble opinion For this kind of jars it is best you embed Database and save exec time and port usage in Db and compare usage time and restrict it . The timer approach is not safe due to system time diff or antivirus res or system time allocation res and etc. However for monitor web you can WatchDog app to handle this kind of problem ,

public class Watchdog implements Runnable {

private Vector observers = new Vector(1);
private long timeout = -1;
private volatile boolean stopped = false;
public static final String ERROR_INVALID_TIMEOUT = "timeout less than 1.";

/**
 * Constructor for Watchdog.
 * @param timeout the timeout to use in milliseconds (must be >= 1).
 */
public Watchdog(long timeout) {
    if (timeout < 1) {
        throw new IllegalArgumentException(ERROR_INVALID_TIMEOUT);
    }
    this.timeout = timeout;
}

public void addTimeoutObserver(TimeoutObserver to) {
    observers.addElement(to);
}

public void removeTimeoutObserver(TimeoutObserver to) {
    //no need to synchronize, as Vector is always synchronized
    observers.removeElement(to);
}

protected final void fireTimeoutOccured() {
    Enumeration e = observers.elements();
    while (e.hasMoreElements()) {
        ((TimeoutObserver) e.nextElement()).timeoutOccured(this);
    }
}

/**
 * Start the watch dog.
 */
public synchronized void start() {
    stopped = false;
    Thread t = new Thread(this, "WATCHDOG");
    t.setDaemon(true);
    t.start();
}

/**
 * Stop the watch dog.
 */
public synchronized void stop() {
    stopped = true;
    notifyAll();
}


public synchronized void run() {
    final long until = System.currentTimeMillis() + timeout;
    long now;
    while (!stopped && until > (now = System.currentTimeMillis())) {
        try {
            wait(until - now);
            Boolean SafeToContinue=CheckDbCountDay();
           if(SafeToContinue)
            ExecJarUsingStrategyPattern(new StrategyDoIt());
           else ExecJarUsingStrategyPattern(new showMessage());

        } catch (InterruptedException e) {
            callBack("plz call support");
        }
    }
    if (!stopped) {
        fireTimeoutOccured();
    }
    }

}
Ali.Mojtahed
  • 2,537
  • 1
  • 15
  • 23
1

If I understand correctly you have different virtual machines that execute the same jar/code (that I will call operation). If so you could setup a locking mechanism, independent from those VM. For example you could use a file but better use the DB and its native locking features: create a "Locks" (ID, version, operation, expiration) table then each time the operation executes attempt to retrieve a Lock row for the operation, if row doesn't exist or is expired then create/update a Lock row setting expiration and allow the operation, otherwise throw cannot-execute-since-locked exception. Expiration is used for avoiding locking forever if the operation crashes, as finally could not be executed (eg: OS crashes). To avoid double/concurrent writing you should use DB optimistic locking feature for the Lock table, eg: a Version field. Release the lock at the end of operation deleting the row. Lock rows must be created and deleted in distinct transactions, separate from those of the operation (if any)

Testo Testini
  • 2,200
  • 18
  • 29
1

Essentially what you need is a lock, that works across jvms. Or, lets say, a way to share object between jvms so that you can take a lock on them. There are multiple solutions available here, like creating a file to indicate a lock, or a database based lock if you already have a database in your application, or a distribute lock. Terracotta is one possible solutions here. You can try apache zookeeper as well, and curator library, again from apache, makes it super easy to use.

Zookeeper and curator: the code looks as simple as:

lock = new InterProcessSemaphoreMutex(client, lockPath);
lock.acquire(5, TimeUnit.MINUTES);
// do something
lock.release();

Complete example: here

Sourabh
  • 429
  • 1
  • 4
  • 11
1

Best way to do it would be to use database . At start of app lock a particular row (using for update for safety in case both start at same time) and write in_use there in some column . Then do you business ,once done update the same row from in_use to completed . In this way at a particular time on one instance of your jar will execute you business code .Also it will not fail in case both are in different machines .

gladiator
  • 1,249
  • 8
  • 23
1

You could check if a files exists in order to signal that the .jar is executing and if yes terminate :

import java.io.File;
import java.io.IOException;

public class Main {

public static void main(String[] args) {


    if (FileLock.exists()){
        System.out.println("The file exists so the jar is running");
        System.exit(0);
    }


    FileLock.createLockFile();

    //start Running the .Jar File
    /*
     * 
     * 
     * CODE
     * 
     * 
     * 
     */


    //Delete the file when the program terminates
    FileLock.deleteLockFile();
    System.out.println("Program exiting normally");
}

}

class FileLock {

private static File lock = new File("jar-running.txt");

public static boolean exists()
{
    return lock.exists();
}

public static void createLockFile()
{
  try {

    lock.createNewFile();

} catch (IOException e) {

    // the file already exists
    System.exit(0);}
}

public static void deleteLockFile()
{
    if(lock.exists()) lock.delete();
}

}

firephil
  • 830
  • 10
  • 18