2012年4月4日水曜日

commons-daemon 第2回

まずはjavaソースから。 以下のwikiを参考にしてます。

参考 Daemon - Commons Wiki

ただ、肝心な部分がよく分からなかったので、カスタマイズしてます。 まずは、Daemonインターフェースを実装したクラス。
EngineLauncher クラスが本体で、こいつがEngine(インターフェースを実装した)クラスを起動してメイン処理を実行します。
停止するときも、Engine(インターフェースを実装した)クラスを停止します。

EngineLauncher

Windowsのサービスとして動くときは、windowsServiceを使用します。
procrun.exeは、public staticメソッドしか呼ぶことができません。
そして、実行時には引数を渡すことができますので
開始時には、"start"、停止時には"stop"を渡すことで、それぞれstartWindowsServiceとstopWindowsServiceメソッドを呼び出します。

mainメソッドはおまけです。使用しません。

Linuxで使用するjsvcでは、Daemonインターフェースを実装していると、
最初にinitが呼ばれ、続いてstartメソッドが呼ばれます。
停止するときは、"-stop"オプションをつけてjsvcを実行することでstopメソッドが呼び出されます。

  1. package jp.tanakanbb.blogspot.daemon.service.sample;  
  2.   
  3. import java.util.Scanner;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6.   
  7. import jp.tanakanbb.blogspot.daemon.service.sample.impl.SampleEngineImpl;  
  8.   
  9. import org.apache.commons.daemon.Daemon;  
  10. import org.apache.commons.daemon.DaemonContext;  
  11. import org.apache.commons.logging.Log;  
  12. import org.apache.commons.logging.LogFactory;  
  13.   
  14. public class EngineLauncher implements Daemon {  
  15.   
  16.     /** 
  17.      * ログ 
  18.      */  
  19.     private static Log LOG = LogFactory.getLog(EngineLauncher.class);  
  20.   
  21.     /** 
  22.      * エンジン 
  23.      */  
  24.     private static Engine engine = null;  
  25.   
  26.     /** 
  27.      * エンジン起動 
  28.      */  
  29.     private static EngineLauncher engineLauncherInstance = new EngineLauncher();  
  30.   
  31.     /** 
  32.      * Executor 
  33.      */  
  34.     private ExecutorService executor = null;  
  35.   
  36.     /** 
  37.      * The Java entry point. 
  38.      * 
  39.      * @param args 
  40.      *            Command line arguments, all ignored. 
  41.      */  
  42.     public static void main(String[] args) {  
  43.         // the main routine is only here so I can also run the app from the  
  44.         // command line  
  45.         engineLauncherInstance.initialize();  
  46.   
  47.         engineLauncherInstance.startWindowsService();  
  48.   
  49.         Scanner sc = new Scanner(System.in);  
  50.         // wait until receive stop command from keyboard  
  51.         System.out.printf("Enter 'stop' to halt: ");  
  52.   
  53.         while (!sc.nextLine().toLowerCase().equals("stop")) {  
  54.             ;  
  55.         }  
  56.   
  57.         engineLauncherInstance.stopWindowsService();  
  58.   
  59.     }  
  60.   
  61.     /** 
  62.      * Windowsサービスを起動します。 
  63.  
  64.      * サービス登録するときのパラメータは次のようです。 
  65.      * 
  66.      * <pre> 
  67.      * --StartMode=jvm --StartClass=jp.tanakanbb.blogspot.daemon.service.sample.EngineLauncher --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass=jp.tanakanbb.blogspot.daemon.service.sample.EngineLauncher --StopMethod=windowsService --StopParams=stop 
  68.      * </pre> 
  69.      * 
  70.      * Windowsサービス、つまりprocrunで起動する場合、実行するメソッドは"public static void"である必要があります。 
  71.  
  72.      * voidでなくてもいいかもしれませんが、戻り値を解釈しないので、voidがいいと思います。 
  73.      * 
  74.      * @param args 
  75.      *            Arguments from prunsrv command line 
  76.      **/  
  77.     public static void windowsService(String args[]) {  
  78.         String cmd = "start";  
  79.         if (args.length > 0) {  
  80.             cmd = args[0];  
  81.         }  
  82.   
  83.         if ("start".equals(cmd)) {  
  84.             engineLauncherInstance.startWindowsService();  
  85.         } else {  
  86.             engineLauncherInstance.stopWindowsService();  
  87.         }  
  88.     }  
  89.   
  90.     /** 
  91.      * Windowsサービスの場合のスタートメソッド。 
  92.  
  93.      * Engine#execute()を起動します。 
  94.      */  
  95.     public void startWindowsService() {  
  96.         if (LOG.isDebugEnabled()) {  
  97.             LOG.debug("startWindowsService called");  
  98.         }  
  99.   
  100.         initialize();  
  101.         // don't return until stopped  
  102.         executor.execute(engine);  
  103.     }  
  104.   
  105.     /** 
  106.      * Windowsサービスを停止します。 
  107.      */  
  108.     public void stopWindowsService() {  
  109.         if (LOG.isDebugEnabled()) {  
  110.             LOG.debug("stopWindowsService called");  
  111.         }  
  112.   
  113.         terminate();  
  114.   
  115.         executor.shutdown();  
  116.     }  
  117.   
  118.     /** 
  119.      * Implementing the Daemon interface is not required for Windows but is for 
  120.      * Linux 
  121.  
  122.      * jsvcでの起動時に最初に呼ばれます。 
  123.  
  124.      * {@link Daemon#init(DaemonContext)} 
  125.      */  
  126.     @Override  
  127.     public void init(DaemonContext arg0) throws Exception {  
  128.         LOG.debug("Daemon init");  
  129.     }  
  130.   
  131.     /** 
  132.      * jsvcでの起動時に、{@link Daemon#init(DaemonContext)}の次に呼ばれます。 
  133.      */  
  134.     @Override  
  135.     public void start() {  
  136.         if (LOG.isDebugEnabled()) {  
  137.             LOG.debug("Daemon start");  
  138.         }  
  139.         initialize();  
  140.     }  
  141.   
  142.     /** 
  143.      * jsvcでの-stopオプション時に呼ばれます。 
  144.      */  
  145.     @Override  
  146.     public void stop() {  
  147.         if (LOG.isDebugEnabled()) {  
  148.             LOG.debug("Daemon stop");  
  149.         }  
  150.   
  151.         terminate();  
  152.     }  
  153.   
  154.     /** 
  155.      * {@link Daemon#stop()}後に呼ばれます。 
  156.      */  
  157.     @Override  
  158.     public void destroy() {  
  159.         if (LOG.isDebugEnabled()) {  
  160.             LOG.debug("Daemon destroy");  
  161.         }  
  162.     }  
  163.   
  164.     /** 
  165.      * Engineを初期化します。 
  166.  
  167.      * WindowsでもLinuxでも、最初にこれを呼ぶ必要があります。 Do the work of starting the engine 
  168.      */  
  169.     private void initialize() {  
  170.         if (engine == null) {  
  171.             if (LOG.isInfoEnabled()) {  
  172.                 LOG.info("Starting the Engine");  
  173.             }  
  174.             engine = new SampleEngineImpl();  
  175.         }  
  176.   
  177.         executor = Executors.newSingleThreadExecutor();  
  178.     }  
  179.   
  180.     /** 
  181.      * Windowsサービス、デーモンを停止します。 WindowsでもLinuxでも、停止時には、これを呼ぶ必要があります。 Cleanly stop 
  182.      * the engine. 
  183.      */  
  184.     public void terminate() {  
  185.         if (engine != null) {  
  186.             if (LOG.isInfoEnabled()) {  
  187.                 LOG.info("Stopping the Engine");  
  188.             }  
  189.   
  190.             engine.stop();  
  191.   
  192.             if (LOG.isInfoEnabled()) {  
  193.                 LOG.info("Engine stopped");  
  194.             }  
  195.         }  
  196.     }  
  197.   
  198. }  

Engine


  1. package jp.tanakanbb.blogspot.daemon.service.sample;  
  2.   
  3. public interface Engine extends Runnable {  
  4.   
  5.     public void stop();  
  6.   
  7.     public Boolean isStopped();  
  8.   
  9. }  

SampleEngineImpl


  1. package jp.tanakanbb.blogspot.daemon.service.sample.impl;  
  2.   
  3. import jp.tanakanbb.blogspot.daemon.service.sample.Engine;  
  4.   
  5. import org.apache.commons.logging.Log;  
  6. import org.apache.commons.logging.LogFactory;  
  7.   
  8. public class SampleEngineImpl implements Engine {  
  9.   
  10.     /** 
  11.      * ログ 
  12.      */  
  13.     private static Log LOG = LogFactory.getLog(SampleEngineImpl.class);  
  14.   
  15.     /** 
  16.      * 停止フラグ 
  17.      */  
  18.     private Boolean isStopped = Boolean.FALSE;  
  19.   
  20.     /** 
  21.      * スレッドID 
  22.      */  
  23.     private String id = null;  
  24.   
  25.     @Override  
  26.     public void stop() {  
  27.         this.isStopped = Boolean.TRUE;  
  28.     }  
  29.   
  30.     @Override  
  31.     public Boolean isStopped() {  
  32.         return isStopped;  
  33.     }  
  34.   
  35.     @Override  
  36.     public void run() {  
  37.   
  38.         this.id = String.valueOf(Thread.currentThread().getId());  
  39.   
  40.         while (!isStopped()) {  
  41.             if (LOG.isInfoEnabled()) {  
  42.                 LOG.info("[" + id + "]" + "hoge");  
  43.             }  
  44.   
  45.             try {  
  46.                 Thread.sleep(10000);  
  47.             } catch (InterruptedException e) {  
  48.                 isStopped = Boolean.TRUE;  
  49.                 if (LOG.isErrorEnabled()) {  
  50.                     LOG.error(e);  
  51.                 }  
  52.             }  
  53.         }  
  54.     }  
  55.   
  56. }  
さて、第3回では、Windowsサービスへの登録方法とLinuxデーモン化方法を書きたいと思います。

0 件のコメント:

コメントを投稿