/*******************************************************************************
 *
 * 只运行一个实例
 *
 * Just single instance
 *
 *
 * Author: NeedJava
 *
 * Modified: 2007.08.29
 *
 *
 * 你可以使用此程序于任何地方,但请保留程序作者及注释的完整。如果你改进了程序,
 *
 * 请在原作者后添加姓名,如:Author: NeedJava/Jack/Mike,版本及修改时间同理。
 *
 ******************************************************************************/
public final class SingleInstance
{
  /*****************************************************************************
   *
   * 构造函数
   *
   ****************************************************************************/
  private SingleInstance()
  {
    this( "vab", ".vab", "vab" );
  }
						
								
  public SingleInstance( String filePrefixName, String fileSuffixName, String directoryName )
  {
    this.init( filePrefixName, fileSuffixName, directoryName );
  }
						
								
  /*****************************************************************************
   *
   * 原理:
   *
   * 用重定向将标准错误输出流定向到一个日志文件,占用它,使其不能被删除
   *
   * 以后的实例试图将存在的此日志文件改名并且另存为某个文件夹下
   *
   * 如果成功,说明没有程序占用它(不排除你在用它,缺陷?),正好保存日志
   *
   * 如果不成功,退出、renameTo命令有一箭双雕的作用
   *
   ****************************************************************************/
  private final void init( String filePrefixName, String fileSuffixName, String directoryName )
  {
    if( filePrefixName==null||fileSuffixName==null||directoryName==null )
      {
        exitWithWarning( "Error: Invalid file name.", 10 );
      }
						    //We need check the fileSuffixName here? From the tail?
						    String fileName=filePrefixName+fileSuffixName;
						    try{ File error=new File( fileName );
						         if( error.exists() )
           {
             File directory=new File( directoryName );
						             String newFileName=directoryName+File.separator+convertMillisecond2DateTime( error.lastModified() )+fileSuffixName;
						             //System.out.println( newFileName );
						             if( directory.exists() )
               {
                 if( directory.isDirectory() )
                   {
                     //renameTo也是好东东,既可以改名,还可以移文件
                     if( !error.renameTo( new File( newFileName ) ) )
                       {
                         exitWithWarning( "Error: The instance already exists, I will exit.", 11 );
                       }
                   }
                 else{ exitWithWarning( "Error: The \'"+directoryName+"\' is not a valid directory.", 21 );
                     }
               }
             else{ if( directory.mkdirs() )
                     {
                       //renameTo也是好东东,既可以改名,还可以移文件
                       if( !error.renameTo( new File( newFileName ) ) )
                         {
                           exitWithWarning( "Error: The instance already exists, I will exit.", 11 );
                         }
                     }
                   else{ exitWithWarning( "Error: Failed to create the \'"+directoryName+"\' directory.", 22 );
                       }
                 }
           }
						         //重定向标准错误输出流,所有功能全靠它。来,啵一个
         System.setErr( new PrintStream( new FileOutputStream( fileName ) ) );
       }
    catch( FileNotFoundException fnfe )
         {
           //fnfe.printStackTrace();
						           exitWithWarning( fnfe.toString(), 23 );
         }
    catch( IOException ioe )
         {
           //ioe.printStackTrace();
						           exitWithWarning( ioe.toString(), 29 );
         }
    catch( Exception e )
         {
           //e.printStackTrace();
						           exitWithWarning( e.toString(), 99 );
         }
  }
						
								
  /*****************************************************************************
   *
   * You can change the milliseconds to the date and time string here
   *
   * I just return the original
   *
   * Don't get the same string :)
   *
   ****************************************************************************/
  private final String convertMillisecond2DateTime( long millisecond )
  {
    return ""+millisecond;
  }
						
								
  /*****************************************************************************
   *
   * Return the warning and the exit code, then exit the application
   *
   ****************************************************************************/
  private final void exitWithWarning( String warning, int code )
  {
    System.out.println( warning==null ? "" : warning );
						    System.exit( code );
  }
						
								
  /*****************************************************************************
   *
   * 主函数入口
   *
   ****************************************************************************/
  public final static void main( String[] args )
  {
    SingleInstance si=new SingleInstance( "error", ".txt", "error" );
						    final JFrame frame=new JFrame( "Just single instance. By NeedJava. 2007.08.29" );
						    //I stay here, to make some friends happy.
    frame.addWindowListener( new WindowAdapter()
    {
      public void windowClosing( WindowEvent we )
      {
        frame.dispose();
						        System.exit( 0 );
      }
    } );
						    frame.setBounds( 200, 200, 700, 70 );
						    frame.setVisible( true );
  }
}