package com.mindprod.example;
import javax.swing.JOptionPane;
import java.awt.EventQueue;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.nio.charset.StandardCharsets;
import static java.lang.System.*;
/**
* First cut to arrange for single instance using UDP.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2013-01-08 initial version
* @since 2013-01-08
*/
public class Exclusive implements Runnable
{
private final InetAddress group;
private final MulticastSocket socket;
private final int port;
private final long myTime;
private volatile Thread thread;
private volatile boolean runFlag;
/**
* constructor
*
* @param ipStr multicast IP
* @param portStr port
*
* @throws IOException
*/
public Exclusive( String ipStr, String portStr ) throws IOException
{
myTime = System.currentTimeMillis();
group = InetAddress.getByName( ipStr );
port = Integer.parseInt( portStr );
socket = new MulticastSocket( port );
socket.joinGroup( group );
}
/**
* abort. Another instance is already running
*/
private void stop()
{
if ( thread != null && thread.isAlive() )
{
runFlag = false;
if ( socket != null )
{
socket.close();
}
}
synchronized ( this )
{
notify();
}
}
/**
* main method
*
* @param args not used
*/
public static void main( String[] args )
{
try
{
Exclusive e = new Exclusive( "227.228.229.230", "23222" );
e.start();
if ( e.waitFor() )
{
out.println( "no other copy running!" );
}
else
{
out.println( "another copy is running" );
}
}
catch ( IOException | InterruptedException ex )
{
ex.printStackTrace();
}
}
@Override
/** implements Runnable */
public void run()
{
while ( runFlag )
{
try
{
byte[] buf = new byte[ 64 ];
DatagramPacket dp = new DatagramPacket( buf, buf.length );
socket.receive( dp );
String timeStr = new String( dp.getData(), dp.getOffset(),
dp.getLength(), StandardCharsets.US_ASCII );
long theirTime = Long.parseLong( timeStr );
if ( theirTime == myTime )
{
}
else if ( theirTime < myTime )
{
stop();
shutdownHook();
}
else if ( theirTime > myTime )
{
String str = Long.toString( myTime );
buf = str.getBytes( StandardCharsets.US_ASCII );
dp = new DatagramPacket( buf, buf.length, group, port );
socket.send( dp );
}
}
catch ( IOException | NumberFormatException ex )
{
ex.printStackTrace();
stop();
}
}
}
/**
* schedule dialog on shutdown
*/
public void shutdownHook()
{
try
{
EventQueue.invokeAndWait( new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog( null,
"Another copy of this program is already running",
"Start Inhibited", JOptionPane.ERROR_MESSAGE );
}
} );
}
catch ( InterruptedException | InvocationTargetException ex )
{
ex.printStackTrace();
}
}
/**
* probe to see if other instance already running
*/
public void start() throws IOException
{
if ( thread == null || !thread.isAlive() )
{
runFlag = true;
thread = new Thread( this );
thread.start();
String str = Long.toString( myTime );
byte[] buf = str.getBytes( StandardCharsets.US_ASCII );
DatagramPacket dp =
new DatagramPacket( buf, buf.length, group, port );
socket.send( dp );
}
}
/**
* wait for two seconds to delay program startup until we have
* time to determine if there is another copy running.
* returns true if no other copy is running.
*/
public synchronized boolean waitFor() throws InterruptedException
{
wait( 2000 );
return runFlag;
}
}