2014年7月24日木曜日

[MySQL] 外部から接続するのに失敗しまくった(ファイアウォール、my.cnf、権限)

LinuxにインストールしたMySQLに外部から接続するのに何度も失敗して結構時間食った。

ファイアウォールでやらかす

まず最初のエラー。下記コマンドを試みる。
C:\Users\>mysql -u <MySQLのユーザ> -h '<DBサーバIP>' -p
Enter password: *********
すると、
ERROR 2003 (HY000): Can't connect to MySQL server on '<クライアントIP>' (10060)
"Can't connect to MySQL server" でググった結果、DBサーバのファイアウォールの設定では?とのこと。
iptables -L
して設定状況を確認する。
INPUTチェインでREJECTしているルールがあったので削除。
(本来はダメだろうけど、とりあえず問題を切り分ける為に実施)

my.cnf でやらかす

再度接続を試みると、
ERROR 1042 (HY000): Can't get hostname for your address
またググる。
MySQLの設定ファイル my.cnf に下記を追加すれば良いらしい。
skip-name-resolve
↓の通り追加した。
[mysqld]
(略)
skip-name-resolve
(略)

権限でやらかす

再度接続を試みると、
ERROR 1130 (HY000): Host '<クライアントIP>' is not allowed to connect to this MySQL server
またググる。
ログインを試みているユーザに、クライアントPCからアクセスする権限を付与しないといけないらしい。
GRANT ALL PRIVILEGES ON *.* TO <MySQLユーザ>@'<クライアントIP>' IDENTIFIED BY '<パスワード>' WITH GRANT OPTION;
実際はデータベースやテーブルをちゃんと指定する必要あり。。 これでようやく…
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.5.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

【参考】

MySQLで外部から接続するときにチェックする項目 - yummy-yummy
MySQL を外部接続できるようにする - 怠惰な日々
Linuxコマンド集 - 【iptables】パケットフィルタリングを設定する:ITpro

2014年7月13日日曜日

[S2Chronos] リクエストをトリガーにTaskを非同期実行

本来の使い方に即しているかわからないけど、S2Chronosで非同期処理が簡単に実現できる。

前回書いた記事の通りに設定を行った後、リクエストをトリガーにTaskを非同期実行するプログラムを書いた。
package org.seasar.example.action;

import javax.annotation.Resource;

import org.seasar.chronos.core.Scheduler;
import org.seasar.example.task.SampleTask;
import org.seasar.framework.log.Logger;
import org.seasar.struts.annotation.Execute;

public class IndexAction {

    private static final Logger logger = Logger.getLogger(IndexAction.class);

    @Resource
    private Scheduler scheduler;

    @Execute(validator = false)
    public String index() throws InterruptedException {

         // タスク登録
         // 登録後、Chronosがプールしている別スレッドで自動実行
         scheduler.addTask(SampleTask.class);

        // 実行状況を確認するログ出力
        for (int i=0;i<10;i++) {
            logger.info("アクションの処理実行中 " + i);
            Thread.sleep(1000);
        }
        return "index.jsp";
    }

}
package org.seasar.example.task;

import org.seasar.chronos.core.annotation.task.Task;
import org.seasar.chronos.core.annotation.task.method.NextTask;
import org.seasar.chronos.core.annotation.trigger.NonDelayTrigger;
import org.seasar.framework.log.Logger;

@Task(autoSchedule=false)
@NonDelayTrigger
public class SampleTask {

    @NextTask("test")
    public static void doExecute() throws InterruptedException {

        // 実行状況を確認するログ出力
        for (int i=0;i<10;i++) {
            logger.info("タスクの実行中 " + i);
            Thread.sleep(800);
        }
    }

    private static final Logger logger = Logger.getLogger(SampleTask.class);

    public void initialize() {
        logger.info("[initialize]");
    }

    public void start() {
        logger.info("[start]");
    }

    public void finish() {
        logger.info("[finish]");
    }

    public void destroy() {
        logger.info("[destroy]");
    }
}
ブラウザからリクエストを送信した結果が下記。 非同期処理が実現されている。
DEBUG 2014-07-13 21:40:30,588 [http-bio-8080-exec-8] BEGIN org.seasar.example.action.IndexAction#index()
DEBUG 2014-07-13 21:40:30,599 [http-bio-8080-exec-8] トランザクションを開始しました。tx=[FormatId=4360, GlobalId=1405255230598/0, BranchId=]
DEBUG 2014-07-13 21:40:30,599 [http-bio-8080-exec-8] BEGIN org.seasar.chronos.core.impl.SchedulerImpl#addTask(class org.seasar.example.task.SampleTask)
DEBUG 2014-07-13 21:40:30,604 [http-bio-8080-exec-8] END org.seasar.chronos.core.impl.SchedulerImpl#addTask(class org.seasar.example.task.SampleTask) : true
INFO  2014-07-13 21:40:30,604 [http-bio-8080-exec-8] アクションの処理実行中 0
INFO  2014-07-13 21:40:31,604 [http-bio-8080-exec-8] アクションの処理実行中 1
INFO  2014-07-13 21:40:32,604 [http-bio-8080-exec-8] アクションの処理実行中 2
INFO  2014-07-13 21:40:33,605 [http-bio-8080-exec-8] アクションの処理実行中 3
DEBUG 2014-07-13 21:40:33,875 [chronos-pool-3-thread-1] BEGIN org.seasar.example.task.SampleTask#initialize()
INFO  2014-07-13 21:40:33,876 [chronos-pool-3-thread-1] [initialize]
DEBUG 2014-07-13 21:40:33,876 [chronos-pool-3-thread-1] END org.seasar.example.task.SampleTask#initialize() : null
INFO  2014-07-13 21:40:34,605 [http-bio-8080-exec-8] アクションの処理実行中 4
INFO  2014-07-13 21:40:35,605 [http-bio-8080-exec-8] アクションの処理実行中 5
DEBUG 2014-07-13 21:40:35,879 [chronos-pool-1-daemonthread-1] タスク (org.seasar.example.task.SampleTask) を 開始します.
DEBUG 2014-07-13 21:40:35,881 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 開始しました.
INFO  2014-07-13 21:40:35,882 [chronos-pool-3-thread-1] [start]
INFO  2014-07-13 21:40:35,886 [chronos-pool-3-thread-1] タスクの実行中 0
INFO  2014-07-13 21:40:36,605 [http-bio-8080-exec-8] アクションの処理実行中 6
INFO  2014-07-13 21:40:36,686 [chronos-pool-3-thread-1] タスクの実行中 1
INFO  2014-07-13 21:40:37,486 [chronos-pool-3-thread-1] タスクの実行中 2
INFO  2014-07-13 21:40:37,605 [http-bio-8080-exec-8] アクションの処理実行中 7
INFO  2014-07-13 21:40:38,286 [chronos-pool-3-thread-1] タスクの実行中 3
INFO  2014-07-13 21:40:38,605 [http-bio-8080-exec-8] アクションの処理実行中 8
INFO  2014-07-13 21:40:39,086 [chronos-pool-3-thread-1] タスクの実行中 4
INFO  2014-07-13 21:40:39,605 [http-bio-8080-exec-8] アクションの処理実行中 9
INFO  2014-07-13 21:40:39,886 [chronos-pool-3-thread-1] タスクの実行中 5
DEBUG 2014-07-13 21:40:40,609 [http-bio-8080-exec-8] トランザクションをコミットしました。tx=[FormatId=4360, GlobalId=1405255230598/0, BranchId=]
DEBUG 2014-07-13 21:40:40,609 [http-bio-8080-exec-8] END org.seasar.example.action.IndexAction#index() : index.jsp
DEBUG 2014-07-13 21:40:40,630 [http-bio-8080-exec-8] 

** after *****************************************: /index.do
  Response class=org.apache.catalina.connector.ResponseFacade, instance=org.apache.catalina.connector.ResponseFacade@413803ba
  [request]indexAction=org.seasar.example.action.IndexAction$$EnhancedByS2AOP$$60223be4@60c0a150
  [request]indexActionForm=org.seasar.struts.action.ActionFormWrapper@447cc9c9
  [request]javax.servlet.forward.context_path=/s2sample
  [request]javax.servlet.forward.request_uri=/s2sample/
  [request]javax.servlet.forward.servlet_path=/
  [request]org.apache.struts.action.MESSAGE=org.seasar.struts.util.S2PropertyMessageResources@5ca3ce3f
  [request]org.apache.struts.action.MODULE=org.seasar.struts.config.S2ModuleConfig@639b99d
  [request]org.apache.struts.action.mapping.instance=ActionConfig[path=/index,name=indexActionForm,scope=request,validate=false,cancellable=false
  [request]org.seasar.struts.util.S2ExecuteConfigUtil=org.seasar.struts.config.S2ExecuteConfig@37c8f59c
  [cookie]JSESSIONID=B594B4C31C8CDCC115905A8A57A739AA
  [cookie]JSESSIONID=560C273D113E86C2FED64320DEADF6AB
  [session]org.apache.struts.action.LOCALE=ja

INFO  2014-07-13 21:40:40,702 [chronos-pool-3-thread-1] タスクの実行中 6
INFO  2014-07-13 21:40:41,502 [chronos-pool-3-thread-1] タスクの実行中 7
INFO  2014-07-13 21:40:42,302 [chronos-pool-3-thread-1] タスクの実行中 8
INFO  2014-07-13 21:40:43,102 [chronos-pool-3-thread-1] タスクの実行中 9
INFO  2014-07-13 21:40:43,903 [chronos-pool-3-thread-1] [finish]
DEBUG 2014-07-13 21:40:43,904 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 終了します.
DEBUG 2014-07-13 21:40:43,905 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 終了しました.
DEBUG 2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] BEGIN org.seasar.example.task.SampleTask#destroy()
INFO  2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] [destroy]
DEBUG 2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] END org.seasar.example.task.SampleTask#destroy() : null
もちろん自分でスレッド作っても同じだけど、こっちのほうがコード少なくてすむ。
また、あまり多くないかもしれないが、契機が時間でなくリクエストとなる(API的な)バッチ処理や、画面からバッチの実行を制御するような場合にはこんな感じで実現すると良さそう。

【環境】

Java SE7
Seasar2.4.45
S2Chronos1.0.0

2014年7月11日金曜日

[VBS][JavaScript][IE操作] 信頼済みゾーンのサイトでIEオブジェクトが動かない

社内システムから定期的に情報を取得してメールを送信するバッチをJavaScriptで実装していると、
"そのインターフェイスは認識されません。"
やら
"エラーを特定できません。"
とのエラーが。 エラー発生箇所を見ると↓の4行目で落ちていた。
var ie = WScript.CreateObject("InternetExplorer.Application");

// IE読み込み待ち
while(ie.Busy or ie.ReadyState <> 4) {
}
エラーメッセージでググって出てきたheipooh's 日記 を見てみると
ゾーンの設定変更で解消したとのことなので、試してみたところうまくいった。

【環境】
Internet Explorer 8
※古い。。

2014年7月8日火曜日

[SAStruts] RequestProcessor 内で Action やMethod のインスタンスを取得する

Seasar2のS2RequestProcessorを拡張しての共通処理に挑戦中。

やりたいことは殆ど『Seasar2 徹底入門』の「6.5 認証処理を実装する」の通りだけども、自前の処理を書くと途端に戸惑う。
特に、呼び出されるMethodやActionの取得方法がわからなくて困った。
調べる前にS2RequestProcessorのソースを見てたら類似の処理があったので、おそらくこれかな~。
// Actionの取得
S2ActionMapping s2mapping = S2ActionMappingUtil.getActionMapping();
Object action = s2mapping.getAction();
やりたい共通処理は認証で、自前のAbstractActionを継承したActionにのみ行いたい処理を今回のRequestProcessorに書くつもり。

認証を行う対象はアノテーションでマーキングすべきかと思ったけど、AbstractActionに認証用のDtoを定義している。
その為、↑で取得したActionのプロパティを見て対象を判定することにする。
// Methodの取得
S2ExecuteConfig executeConfig = S2ExecuteConfigUtil.getExecuteConfig();
Method method = executeConfig.getMethod();
なんとなく、org.seasar.struts.utilパッケージのユーティリティが鍵っぽい。

SAどころかStrutsの中身もちゃんと見たことないので、この機会にもう少し学んでみよう。

2014年7月4日金曜日

[Seasar2] S2Chronos1.0.0 のセットアップが公式通りだとうまくいかない

"Seasar2に対応したJavaオブジェクトスケジューリングフレームワーク"、S2Chronosの有用性検証を依頼されたのでセットアップ。

公式を見ながら行ったのだが、diconファイルの読み込みあたりでClassNotFoundExceptionなんかが頻発。。いくつかのblogを参考にしてみると公式に記載の無い設定が必要だったりした。

以下、インストールに要した全作業。

1. S2Choronosのjarファイルを↓からダウンロード。WEB-INF/lib に配置し、ビルドパスに加える。
 http://s2chronos.sandbox.seasar.org/ja/download.html

 ソースは下記から。
 http://maven.seasar.org/maven2/org/seasar/chronos/s2chronos-core/1.0.0/
 http://maven.seasar.org/maven2/org/seasar/chronos/s2chronos-extension/1.0.0/


2.chronosCustomize.dicon を作成し、 src/main/resource に配置する。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components>
    <component name="schedulerConfiguration" class="org.seasar.chronos.core.SchedulerConfiguration">
        <property name="hotdeployDisable">true</property>
        <property name="daemon">true</property>
        <property name="autoFinish">false</property>
        <property name="autoFinishTimeLimit">5000L</property>
        <property name="taskScanIntervalTime">2000L</property>
        <property name="threadPoolType">@org.seasar.chronos.core.ThreadPoolType@CACHED</property>
    </component>
</components>
※ chronosCustomizer.dicon ではないので要注意。
※ パッケージ名のorg.seasar.chronos.coreが公式だと org.seasar.chronos.core.model になっている。1.0.0ではmodelというパッケージは存在しないので修正する。

3. creator.dicon の<components>タグ中に下記を追記する。
<component class="org.seasar.chronos.core.creator.TaskCreator"/>
<component class="org.seasar.chronos.core.creator.TriggerCreator"/>
4. customizer.dicon の<components>タグ中に下記を追記する。
 <component name="taskSupportAspectCustomizer" class="org.seasar.framework.container.customizer.AspectCustomizer">
   <initMethod name="addInterceptorName">
    <arg>"aop.traceInterceptor"</arg>
   </initMethod>
   <property name="pointcut">"do.*, initialize, destroy"</property>
 </component>
 <component name="taskCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
  <initMethod name="addCustomizer">
   <arg>taskSupportAspectCustomizer</arg>
  </initMethod>
 </component>
 <component name="triggerSupportAspectCustomizer" class="org.seasar.framework.container.customizer.AspectCustomizer">
  <initMethod name="addInterceptorName">
   <arg>"aop.traceInterceptor"</arg>
  </initMethod>
  <property name="pointcut">".*"</property>
 </component>
 <component name="triggerCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
  <initMethod name="addCustomizer">
   <arg>triggerSupportAspectCustomizer</arg>
  </initMethod>
 </component>
5. app.diconの<components>タグ中に下記を追記する。
<include path="chronos-extension.dicon"/>
※ 公式に記述なし。

6. web.xml の<web-app>タグ中に下記を追記する。
<servlet>
    <servlet-name>chronosServlet</servlet-name>
    <servlet-class>org.seasar.chronos.extension.servlet.S2ChronosServlet</servlet-class>
    <load-on-startup>3</load-on-startup>
</servlet>
※ 公式に記述なし。

これでTomcatを起動する。記述に間違いがある場合はコンソールにログが出力されるので確認する。当たり前だが、エラー発生時にはException名よりもどのファイルの読み込み時に落ちているのかに着目して追うと原因を突き止めやすい。

【環境】

Java SE7
Seasar2.4.45
S2Chronos1.0.0
※ そもそもJava SE5までしかサポートしていない模様。

[Java] アプリケーションの実行環境(ホスト名, IPなど)を取得する

java.net.InetAddressクラスを利用することでアプリケーションの実行されているマシン名を取得できる。
import java.net.InetAddress;

// ホスト名取得はこれだけ
System.out.println(InetAddress.getLocalHost().getHostName());
他にもIPアドレスを取得したりできる。

Webアプリケーションだと、AP起動時にホスト名から実行されている環境を判定してメモリに保持しておくなどの使い道がありそう。 ソースで環境毎の分岐を記述することで、環境依存ファイルを少し減らせる…かも。
例えば、起動時に以下のようなクラスをロードしておく。Singletonだと良さそう。
import java.net.InetAddress;
import java.net.UnknownHostException;

public class RuntimeEnvironment {

 private static RuntimeEnvironment instance = new RuntimeEnvironment();
 private RuntimeEnvironment() {}

 private static String hostName;
 private static InetAddress inetAddress;

 public static void init() {
  try {
   inetAddress = InetAddress.getLocalHost();
  } catch (UnknownHostException e) {}
  hostName = inetAddress.getHostName();

 }

 public static String getHostName()             {return hostName;}
 public static InetAddress getInetAddress() {return inetAddress;}

        // 以下、用意する環境を表す列挙型を定義するなど…

}




【環境】

 Java SE7