まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

2014年10月

CentOS で(Eclipseを使って) Java の開発環境を整備するまでの手順を紹介します。
Eclipse を使うので、CentOS には X Window やデスクトップといったモジュールが導入されていることが必要です。


まず Eclipse のインストールそのものは簡単です。JDK を導入した上で最新版をダウンロードして展開してもいいですし、最新版でなくてもよければもっと簡単に yum でインストールすることもできます(以下、こちらの手順を使っている前提で紹介を続けます):
# yum install eclipse

yum を使う場合であれば JDK ごとインストールされてます。なお、2014/10/22 現在ですが、この方法でインストールされる Eclipse のバージョンは 3.6.1(Helios) でした。


加えてウェブアプリケーションの動作確認のため FireFox も導入しておきます:
# yum install firefox

インストールが完了したら、デスクトップのメニューから アプリケーション > プログラミング > Eclipse で起動できます:
2014102101


初回起動時はワークスペースをどのディレクトリに作るか聞かれます。特に理由がなければデフォルトのままでも構いません。"Use this as the default and do not ask again" にチェックを入れておくと、次回起動時にこの質問は聞かれなくなります:
2014102102


Eclipse が初回起動した時の画面です。チュートリアルなどは飛ばして、"Workbench" をクリックし、実際の作業画面に移ります:
2014102103


実際にコーディングを行う作業画面がこちらです。最初の段階では何もプロジェクトがないのでのっぺらぼうですが、ここに作業するプロジェクトを追加していくことになります:
2014102104


ただ、この段階ではまだ Eclipse に充分なプラグインが導入されていないため、Java のウェブアプリケーションを作るウィザードも使えませんし、デバッグ用のウェブアプリケーションサーバーも含まれていません。最低限必要な環境を追加していく必要があります。

Eclipse 作業画面のメニューから Help > Install New Software を選択して、プラグインの更新ダイアログを表示します。そして Work with: 欄に使っている Eclipse のバージョンに合わせた更新サイト(3.6.1 であれば http://download.eclipse.org/releases/helios)を指定します。しばらく待つと下に更新可能なプラグインの候補がカテゴリーに分類されて表示されます:
2014102105


ここから必要なものを選択してチェックを付けていきます。まずは "General Purpose Tools" に分類されている "Marketplace Client" にチェック: 
2014102106


続けて "Web, XML, and Java EE Development" に分類されている "Eclipse Java EE Developer Tools" と "Eclipse Web Development Tools" の両方に(上記と併せて3つ)チェックします:
2014102107


そして Next ボタンを2度クリックし、使用条件を確認した上で accept して、最後に Finish ボタンをクリックすると選択した3つのプラグインの導入が開始されます。プラグインの導入が完了すると Eclipse の再起動を促されるので、再起動("Restart Now")します。再起動後はこの3つのプラグインが有効になった状態で起動します。

この時点では Java アプリケーションプロジェクトを作成することはできるようになっていますが、まだデバッグ用のアプリケーションサーバーが用意されていません。Apache Tomcat などを別途導入してもいいのですが、ここでは簡単に導入できる Jetty をインストールして Eclipse 内から使えるようにします。


Eclipse の再起動後、今度はメニューから Help > Eclipse Marketplace を選択します(Marketplace も上記で導入しているので、再起動後からは使えるようになっているはずです)。

Marketplace ダイアログが表示されたら Find 欄に "Jetty" と入力して、Jetty 関連のマーケットモジュールを検索します:
2014102108


この結果表示されるモジュールの中から、以下の3つをインストールします:
(1) Eclipse Jetty
(2) Run-Jetty-Run
(3) WebLauncher

Marketplace では3つまとめてインストールすることができないので、これらを1つずつ探して "Install" ボタンをクリックする、と繰り返します。そして3つ全てインストールし終わったら、再度 Eclipse を再起動します。これで準備完了です。


では改めてこの環境で Java アプリケーションを作って動かしてみましょう。Eclipse のメニューから File > New > Project を選択してプロジェクトウィザードを出し、Web の下にある "Dynamic Web Project" を選択して "Next" をクリックします。プロジェクトの名称は適当に("TestWeb" など)入力します。他はデフォルトのまま "Finish" をクリックしてプロジェクトを作成します:
2014102109


このプロジェクトにテスト用の JSP ファイルを1つ追加します。プロジェクト名部分を右クリックして New > File を選択し、このプロジェクトの WebContent フォルダ内に test.jsp というファイルを追加します:
2014102110


追加作成した test.jsp を選択してエディタで開き、以下の様な内容を記入します。単純に現在時刻を表示するだけのページですが、Java を使っているので一応 Java ウェブアプリケーションと言えると思います:
2014102111


では作成したこのアプリケーションを実際に動かしてみましょう。プロジェクトを右クリックして Run As > Run Jetty を選択します:
2014102112


Eclipse 内で Jetty が(デフォルトでは 8080 番ポートで)起動します。これでこのプロジェクトが Jetty から参照できるようになっているので、同一マシンで FireFox を起動し、http://localhost:8080/TestWeb/test.jsp にアクセスしてみます:
2014102113
動作が確認できました。ちゃんと Java ウェブアプリケーションの開発や動作確認までできる環境が揃いました!



以下はオマケですが、せっかく Linux 版 Eclipse をインストールしたので、Windows 版ではできない Terminal 機能を紹介します。Eclipse 内のビューを使ってターミナルコンソールを起動する、というものです。

先程と同様にメニューから Help > Install New Software を選択して、今度は "General Purpose Tools" 以下の "Local Terminal" をチェックしてインストールして、Eclipse を再起動します:
2014102114


再起動後、Eclipse のメニューから Window > Show View > Other を選択し、Terminal の下にある Terminal を選択して OK をクリックします:
2014102115


すると画面右下に "Terminal" という名前のタブが1つ追加されます。まだ有効になっていませんが、ここがターミナルコンソールとして使えるウィンドウになります:
2014102116


実際にコンソールを使うにはタブ内の一番右のアイコン(マウスオーバーすると "New Terminal Connection in Current View" と表示される所)をクリックして、接続設定ダイアログを表示します。特に変更の必要はないので、そのまま OK ボタンをクリックします:
2014102117


ターミナルコンソールが有効になり、シェルとして使えるようになります。これで別窓のシェルにいちいち移動する手間が省けます:
2014102118


ただこの機能がまだ Incubation 段階だからなのかもしれませんが、このターミナルコンソールでは日本語が化けて表示されてしまうようです。日本語の入出力に依存するような自由な使い方はまだできない、という認識の元で使えそうです。






こちらで書いた記事の続きです:
Twitter4J で Twetter の Stream API を使う

上記記事では Twitter 上のツイートをリアルタイムに取得する、という Stream API が一般公開され、Java から利用する場合のサンプルを紹介しました。


折角リアルタイムに取得した情報も、単に表示して終わり、ではつまらないです。後で再利用できるよう、データベースに格納してみます。ただどういったフィルタリングをかけるか(かけないのか)にもよりますが、リアルタイムに取得するツイート情報は、かなり膨大になる可能性があります。つまりそれなりのパフォーマンスを持ったデータストアを用意する必要がある、ということです。

という背景がある中で、今回は Couchbase Server をデータストアとして使ってみます。プログラムとしては先日紹介したこの記事のものをベースとして、取得したツイートを次々に Couchbase Server に格納していく、というロジックに変更します。なお CentOS に Couchbase サーバーを導入する手順についてはこちらの記事を参照してください:
CentOS に Couchbase サーバーを導入する

次にロジック変更のための準備として、こちらの記事を参考に Couchbase の Java SDK をダウンロードして、プロジェクトに追加します:
Java から Couchbase Server にアクセスする

次に、Couchbase Server には JSON データを格納することになるので、Java のオブジェクトを JSON 化するために Gson ライブラリをプロジェクトに追加します。以下のサイトから Gson ライブラリをダウンロード&展開し、gson-2.2.jar をプロジェクトに追加します:
https://google-gson.googlecode.com/files/google-gson-2.2.4-release.zip

更に、取得したツイートを Java オブジェクトとして格納するためのクラスを定義します。ここで定義したクラスのインスタンスとしてツイートを生成し、これを GSON で JSON に変換して Couchbase Server に格納する、という流れになります:
import java.util.Date;

public class Tweet {
	private long id;
	private long userid;
	private String username;
	private String text;
	private Date created;
	private Double lat;
	private Double lng;
	private String[] urls;
	private String[] medias;

	public Tweet( long id, long userid, String username, String text, Date created, Double lat, Double lng, String[] urls, String[] medias ){
		this.id = id;
		this.userid = userid;
		this.username = username;
		this.text = text;
		this.created = created;
		this.lat = lat;
		this.lng = lng;
		this.urls = urls;
		this.medias = medias;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public long getUserid() {
		return userid;
	}

	public void setUserid(long userid) {
		this.userid = userid;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Double getLat() {
		return lat;
	}

	public void setLat(Double lat) {
		this.lat = lat;
	}

	public Double getLng() {
		return lng;
	}

	public void setLng(Double lng) {
		this.lng = lng;
	}

	public String[] getUrls() {
		return urls;
	}

	public void setUrls(String[] urls) {
		this.urls = urls;
	}

	public String[] getMedias() {
		return medias;
	}

	public void setMedias(String[] medias) {
		this.medias = medias;
	}	
}

そして、先日の記事で作成した Stream クラスを以下のように書き換えます(変更箇所を青くしています):
import twitter4j.MediaEntity;
import twitter4j.StallWarning;
import twitter4j.Status;
import twitter4j.StatusDeletionNotice;
import twitter4j.StatusListener;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
import twitter4j.URLEntity;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;

public class Streams {

    private static final String CONSUMER_KEY = "(CONSUMER KEY)";
    private static final String CONSUMER_SECRET = "(CONSUMER SECRET)";
    private static final String ACCESS_TOKEN = "(ACCESS TOKEN)";
    private static final String ACCESS_TOKEN_SECRET = "(ACCESS TOKEN SECRET)";

    private static final String COUCHBASE_SERVER = "192.168.X.X"; //. CouchBase Server ホスト

    public static CouchbaseClient conn = null;
    public static Gson gson = null;

    static class MyStatusListener implements StatusListener {

        public void onStatus(Status status) {
            Double lat = null;
            Double lng = null;
            String[] urls = null;
            String[] medias = null;

            //. 位置情報が含まれていれば取得する        	
            GeoLocation location = status.getGeoLocation();
            if( location != null ){
                double dlat = location.getLatitude();
                double dlng = location.getLongitude();
                lat = dlat;
                lng = dlng;
            }
            long id = status.getId(); //. ツイートID
            String text = status.getText(); //. ツイート本文
            long userid = status.getUser().getId(); //. ユーザーID
            String username = status.getUser().getScreenName(); //. ユーザー表示名
            Date created = status.getCreatedAt(); //. ツイート日時
            
            //. ツイート本文にリンクURLが含まれていれば取り出す
            URLEntity[] uentitys = status.getURLEntities();
            if( uentitys != null && uentitys.length > 0 ){
            	List list = new ArrayList();
                for( int i = 0; i < uentitys.length; i ++ ){
                    URLEntity uentity = uentitys[i];
                    String expandedURL = uentity.getExpandedURL();
                    list.add( expandedURL );
                }
	        urls = ( String[] )list.toArray( new String[0] );
            }
            
            //. ツイート本文に画像/動画URLが含まれていれば取り出す
            MediaEntity[] mentitys = status.getMediaEntities();
            if( mentitys != null && mentitys.length > 0 ){
            	List list = new ArrayList();
                for( int i = 0; i < mentitys.length; i ++ ){
                    MediaEntity mentity = mentitys[i];
                    String expandedURL = mentity.getExpandedURL();
                    list.add( expandedURL );
                }
                medias = ( String[] )list.toArray( new String[0] );
            }

            //. 取り出した情報を JSON にして Couchbase に格納する
            Tweet tweet = new Tweet( id, userid, username, text, created, lat, lng, urls, medias );
            conn.set( "" + id, gson.toJson( tweet ) );            
        }

        public void onDeletionNotice(StatusDeletionNotice sdn) {
            //System.out.println("onDeletionNotice.");
        }

        public void onTrackLimitationNotice(int i) {
            //System.out.println("onTrackLimitationNotice.(" + i + ")");
        }

        public void onScrubGeo(long lat, long lng) {
            //System.out.println("onScrubGeo.(" + lat + ", " + lng + ")");
        }

        public void onException(Exception excptn) {
            //System.out.println("onException.");
        }

        public void onStallWarning(StallWarning arg0) {
            // TODO Auto-generated method stub
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Configuration configuration = new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY)
                .setOAuthConsumerSecret(CONSUMER_SECRET)
                .setOAuthAccessToken(ACCESS_TOKEN)
                .setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET)
                .build();

        //. Couchbase Server に接続用
        try{
            List hosts = Arrays.asList( new URI( "http://" + COUCHBASE_SERVER + ":8091/pools" ) );
            conn = new CouchbaseClient( hosts, "default", "" ); //. "Too many open files"
            gson = new Gson();
        }catch( Exception e ){
            e.printStackTrace();
        }

        TwitterStream twStream = new TwitterStreamFactory(configuration).getInstance();
        twStream.addListener(new MyStatusListener());
        
        twStream.sample();
    }
}

前回のコードと比べて、あまり違いはありません。Couchbase SDK を使って Couchbase サーバーに接続するための準備を main メソッド内で行い、onStatus メソッド内では実際に取得したツイートの内容を Java オブジェクト化したものを GSON を使って JSON 化して、後はひたすら ID をキー値として格納する、ということを実行しています。 なお上記コードではフィルタリングを定義していませんが、必要であれば適当なフィルタリング処理を加えていただくのもいいと思います。

このコードを実行すると(フィルタリングの有無や種類にもよりますが)条件に該当するツイートを次々に取得して、Couchbase サーバー内に格納していきます。その様子は Couchbase の管理コンソールからも確認できます:
2014102101

必要に応じて View を定義するなどして、この取得結果を見やすくしたり、別のプログラムから利用できるようにしていく予定です。そちらはまた別途。







 

特別目新しい情報ではなく今更感のある内容ですが、Twitter の Stream 検索 API を使ってみました。

Steam API はいわば「Twitter そのもの」です。自分のタイムラインに関連した内容だけでなく、世界中の Twitter ユーザーがつぶやいた内容をリアルタイムに(Stream として)取得することを目的として提供されています。さすがに全てのツイートを取得するのはごく一部の限られたユーザーにだけ公開されているようですが、一部の(全ツイートの1%程度と言われています)ツイートを取得する API は誰でも使うことができます。一部といっても全て取得していたら、それこそとんでもない量になりますけど・・・

なおずっと以前から公開されていた Twitter の API と区別する場合、Steam API と(従来の)REST API という名称で区別します。


で、その Twitter Stream API を Java から、Twitter4J を使って取得するコードを作って試しに動かしてみました。以下にその様子を紹介します。

まず、何はともあれ Twitter Application Managementへの Developer 登録と、アプリケーションの登録、そして CONSUMER KEY, CONSUMER SECRET, ACCESS TOKEN, ACCESS TOKEN SECRET といった各種キーの取得が必要です。この辺りは REST API の時とも変わらない作業なので、適当にググるなどして調べてください。

次に最新の Twitter4J をダウンロードして展開します。zip アーカイブのファイル名は twitter4j-[バージョン番号].zip です。展開後の lib ディレクトリに含まれる必要なファイル(最低限動かすためには twitter4j-core-[バージョン番号].jar と twitter4j-stream-[バージョン番号].jar の2つのファイル)を開発プロジェクトに取り込むか、CLASSPATH を通して参照可能にします。
2014102001


事前準備はこれでできました。後は以下の様なコードを記述します。冒頭部分で取得した CONSUMER KEY 等のキーに書き換える必要があります。この例では取得する条件を付けず、世の中の全てのツイート(の約1%)をそのまま取得しています。取得イベントが発生する度に onStatus メソッドが呼ばれ、そこで ID やユーザー名、本文といった各種情報を取り出して、最終的には System.out で標準出力しています(実際のアプリではここで DB に格納するなどという流れになると思います):
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import twitter4j.FilterQuery;
import twitter4j.GeoLocation;
import twitter4j.MediaEntity;
import twitter4j.StallWarning;
import twitter4j.Status;
import twitter4j.StatusDeletionNotice;
import twitter4j.StatusListener;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
import twitter4j.URLEntity;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;

public class Streams {

    private static final String CONSUMER_KEY = "(CONSUMER KEY)";
    private static final String CONSUMER_SECRET = "(CONSUMER SECRET)";
    private static final String ACCESS_TOKEN = "(ACCESS TOKEN)";
    private static final String ACCESS_TOKEN_SECRET = "(ACCESS TOKEN SECRET)";

    static class MyStatusListener implements StatusListener {

        public void onStatus(Status status) {
            Double lat = null;
            Double lng = null;
            String[] urls = null;
            String[] medias = null;

            //. 位置情報が含まれていれば取得する        	
            GeoLocation location = status.getGeoLocation();
            if( location != null ){
                double dlat = location.getLatitude();
                double dlng = location.getLongitude();
                lat = dlat;
                lng = dlng;
            }
            long id = status.getId(); //. ツイートID
            String text = status.getText(); //. ツイート本文
            long userid = status.getUser().getId(); //. ユーザーID
            String username = status.getUser().getScreenName(); //. ユーザー表示名
            Date created = status.getCreatedAt(); //. ツイート日時
            
            //. ツイート本文にリンクURLが含まれていれば取り出す
            URLEntity[] uentitys = status.getURLEntities();
            if( uentitys != null && uentitys.length > 0 ){
            	List list = new ArrayList();
                for( int i = 0; i < uentitys.length; i ++ ){
                    URLEntity uentity = uentitys[i];
                    String expandedURL = uentity.getExpandedURL();
                    list.add( expandedURL );
                }
	        urls = ( String[] )list.toArray( new String[0] );
            }
            
            //. ツイート本文に画像/動画URLが含まれていれば取り出す
            MediaEntity[] mentitys = status.getMediaEntities();
            if( mentitys != null && mentitys.length > 0 ){
            	List list = new ArrayList();
                for( int i = 0; i < mentitys.length; i ++ ){
                    MediaEntity mentity = mentitys[i];
                    String expandedURL = mentity.getExpandedURL();
                    list.add( expandedURL );
                }
                medias = ( String[] )list.toArray( new String[0] );
            }

            //. 取り出した情報を表示する(以下では id, username, text のみ)
            System.out.println( "id = " + id + ", username = " + username + ", text = " + text );
        }

        public void onDeletionNotice(StatusDeletionNotice sdn) {
            //System.out.println("onDeletionNotice.");
        }

        public void onTrackLimitationNotice(int i) {
            //System.out.println("onTrackLimitationNotice.(" + i + ")");
        }

        public void onScrubGeo(long lat, long lng) {
            //System.out.println("onScrubGeo.(" + lat + ", " + lng + ")");
        }

        public void onException(Exception excptn) {
            //System.out.println("onException.");
        }

        public void onStallWarning(StallWarning arg0) {
            // TODO Auto-generated method stub
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Configuration configuration = new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY)
                .setOAuthConsumerSecret(CONSUMER_SECRET)
                .setOAuthAccessToken(ACCESS_TOKEN)
                .setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET)
                .build();

        TwitterStream twStream = new TwitterStreamFactory(configuration).getInstance();
        twStream.addListener(new MyStatusListener());
        
        twStream.sample();
    }
}
このサンプルを実行するとツイッター本体が管理するツイートをリアルタイムに(ここ重要!)取得して、目で追えないほど次々に画面出力されていきます。1つ1つの内容を読むことが無理だと思いますが、この様子を眺めているだけで、いかに日本語ツイートの占める割合が高いかもわかると思います:
2014102002


このコードのままだと確かに全ツイート(のランダムな一部)は取得できますが、特定のキーワードやハッシュタグなど、ある特定の目的で絞り込んだツイートだけを集めたいこともあると思います。その場合は main 関数を以下のように書き換えて、フィルタリングを指定します:
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Configuration configuration = new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY)
                .setOAuthConsumerSecret(CONSUMER_SECRET)
                .setOAuthAccessToken(ACCESS_TOKEN)
                .setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET)
                .build();

        TwitterStream twStream = new TwitterStreamFactory(configuration).getInstance();
        twStream.addListener(new MyStatusListener());
        
        //. フィルター
        String[] track = { "wordpress", "#php", "ワードプレス" };
        FilterQuery filter = new FilterQuery();
        filter.track( track );
        twStream.filter( filter );
    }

この例では { "wordpress", "#php", "ワードプレス" } という3つのフィルタを指定しています。これらのキーワードのいずれかが本文に含まれるツイートだけを集めてストリーミングする、という機能に切り替えています。

こちらを実行すると、先ほどのフィルタリングのないケースと比べてかなりゆっくり、少しずつツイートが記録されていく様子がわかると思います:
2014102003


ただこのフィルタリングですが、特に日本語キーワードを正しく取得できる率があまり高くないようです。要は日本語文章の単語分割ロジックが英語の場合と異なることに起因しているのだと思いますが、注意が必要です。ただ日本語のハッシュタグの場合はかなり正しく取得できる、らしいです。


改めて、全レコードではないとはいえ、これだけのリアルタイムビッグデータを誰でも取得できる時代になった、ということだと思います。ビッグデータをリアルタイムに解析する生きたサンプルデータとして、Twitter は最適だと思います。ビッグデータ関連製品もいよいよこれらをどれだけ速く処理して、どれだけ遅れなく格納して、どれだけ最適化して、どれだけ簡易的に扱えるか、という段階になっていくんでしょうかね。

 

IBM Notes を Linux で使いたい、、という需要がどれだけあるかわかりませんが、その導入方法は Windows での場合と比べてちとクセがあります。というわけで、その一連の手順を紹介します。念のため繰り返しますが、Linux にインストールするのは IBM Domino サーバーではなく IBM Notes クライアント、の説明です。


なお、以下で紹介する手順で使う Linux はいろんなクラウドからも提供されていて入手しやすい RHEL(RedHat Enterprise Linux)または CentOS (64bit、バージョンは6)とします。IBM 的には RHEL での動作のみサポートしていて、CentOS はサポート外ですので注意してください。また Notes ID ファイルなどは既に手元にあるものとします。

まず、何はともあれ、RHEL 版(正確には RHEL へのインストールを考慮して用意された rpm 版)の IBM Notes 本体を入手する必要があります。購入するなどして既にお持ち/入手可能な方は読み飛ばしてください。まだお持ちで無い方は無料トライアル版が用意されているのでそちらを使いましょう。IBM developerWorks無料トライアルダウンロードから "Download trial" ボタンをクリックして、IBM ID とパスワード(取得していない場合はこちら(PDF)を参照して無料登録してください)を入力して進んでいくと、どの地域/バージョンの IBM Notes をダウンロードするか、が聞かれます。ここでは現時点で提供されている中では最新版であるバージョン 9.0.1 の "Asia Pacific" 地域を選択して先に進みます:
2014102101


※もちろん英語版を希望する場合は English を選択するなどして、これ以降も適宜読み替えてください。

更に先に進んだ先でサーバー(Domino)かクライアント(Notes)か、プラットフォーム、そして言語を指定します。ここでは Notes クライアントでプラットフォームは rpm 、そして言語に Japanese を選択してダウンロードします。インストール先のシステムが既に用意されている場合は、ダウンロード後は Notes ID などと一緒に SFTP などで転送しておきます:
2014102102


ここでは上記の NC_V9.0.1_LnxRPM_I_JAEva.tar をダウンロードしたものとして、このファイルを目的のサーバーの /tmp 以下に転送済みであるものとします。

次にインストール先システムでの事前準備です。RHEL/CentOS をこれから(ゼロから)インストールするのであれば、最初から日本語デスクトップ利用を前提としたオプションでインストールしてください。AWS など、既に OS がインストール済みのインスタンスを使う場合は、おそらくサーバー用途用の最小構成になっていると思われるので、デスクトップ用に足りないライブラリ等を追加します。具体的には SSH やターミナル等のコマンドラインからこんな感じでしょうか:
# yum groupinstall "X Window System" (X Window)
# yum groupinstall "Desktop" (クライアントデスクトップ)
# yum groupinstall "Japanese Support" (せっかくなので日本語サポート機能も)

日本語サポートまで導入した場合は /etc/sysconfig/i18n を編集して、環境変数 LANG の値を日本語 UTF-8 に指定して再起動します:
LANG="ja_JP.UTF-8"

次に IBM Notes 実行時用のユーザーを作成します。IBM Notes のインストールには root 権限が必要ですが、root ユーザーでは実行できません。別の一般ユーザーが作成済みで、そのユーザーを使うのであればそのユーザーを決めておきます。新たに IBM Notes 実行用のユーザーを作成する必要がある場合は、以下のコマンドで作成します(この例では notesuser というユーザーを新規に作成しています):
# adduser notesuser
# passwd notesuser
  :


また、IBM Notes のインストール作業からはデスクトップ環境が必要になります。必要なライブラリは上記で導入できていますが、SSH などのコマンドラインだけではできない作業が含まれています。実機にアクセスして GNOME のデスクトップを開ける場合はいいのですが、SSH などのリモートコンソールでしか接続出来ない場合は VNC 環境も用意しましょう。RHEL/CentOS への VNC の導入方法についてはこちらを参照ください:
CentOS に VNC サーバーを導入する

これも実機に直接触れる環境があればいいのですが、クラウドなどで VNC 環境を構築する場合の注意点として、上記にもあるように root ユーザーでは IBM Notes を実行できません。一般ユーザー権限で IBM Notes を実行する必要があるため、VNC の接続時にも root 以外の(IBM Notes 用に用意した)一般ユーザーの権限で VNC 接続するよう設定する必要があります。


上記ページの最後の部分までできると、Windows などのリモート環境から今回 IBM Notes をインストールする目的のマシンの GNOME デスクトップが開けるようになっていることになります:



さて、ここからが IBM Notes のインストール作業です。ここからは SSH などのテキストコンソールではなく、実機のモニターや VNC 接続などを使って X Window ベースのデスクトップ環境を開いた上での root 権限で行う必要があります。

まずは IBM developerWorks 等からダウンロードしたインストールモジュールファイルを tar 一時ディレクトリに展開します:
# mkdir /tmp/n9
# cd /tmp/n9
# tar xvf /tmp/NC_V9.0.1_LnxRPM_I_JAEva.tar

展開後のファイルの中に notes.ja.sh(ja 部分は言語によって変わります)というインストール用シェルスクリプトがあるので、これを実行してインストールします。このシェルスクリプトを実行することで必要な rpm を順次導入してくれます:
# ./notes.ja.sh

が、このまま普通に実行すると依存性に関するエラーが大量にでるはずです(実際の出力内容は環境によって異なります): 
エラー: 依存性の欠如:
 gdb は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 tcsh は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libart_lgpl_2.so.2 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libasound.so.2 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libatk-1.0.so.0 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libbonobo-2.so.0 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libbonobo-activation.so.4 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libnonoboui-2.so.0 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
 libcript.so.1 は ibm_notes_9.0.1-20131022.1138.i586 に必要とされています
  :
  :

ここでXXX は ibm_notes_9.0.1-****** に必要とされています」と表示される XXX の部分は、IBM Notes の動作およびインストール時に必要なモジュールであるにも関わらず、まだ同システムに導入されていないもの、いわば「足りないものリスト」です。この内容は同環境に今何がインストールされているか/されていないか によっても変わるので、人によって少なかったり多かったりします。いずれにせよ、ここで表示されるライブラリの一覧を導入しきらない限り IBM Notes はインストールできません。

上記例であれば以下の様な感じで、足りないものを順次、気長に yum でインストールしていきます:
# yum install gdb
# yum install tcsh
# yum install libart_lgpl_2.so.2
# yum install libasound.so.2
#  :

なお、あるモジュールをインストールすることで一緒に他のモジュールが導入されることも珍しくありません(インストール済みだった場合には yum コマンドの結果、"already installed" と表示されます)。エラーとして表示される全てのモジュール回数分だけ繰り返す必要はないと思います。

そして、全ての前提ライブラリの導入が終わったら、再度 IBM Notes のインストールコマンドを実行します:
# ./notes.ja.sh

前提ライブラリの導入漏れがなければインストーラが実行されていきます:
2014102103


Step1 から Step3 までが無事に終わると、インストールは完了です。ちなみにデフォルト設定ではプログラムは /opt/ibm/notes 以下にインストールされています:
2014102104

インストールが完了したので、とうとうセットアップです。ここからは root でない、一般ユーザーの GNOME(X Window) デスクトップ環境で作業することになる点を再度留意してください。

まずメニューから アプリケーション > オフィス(!?) > IBM Notes ができているはずなのでこれを選択します:
2014102105

スプラッシュスクリーンが表示されて、セットアップが開始されます:
2014102106

このようなウィンドウが表われて、使用条件が表示されます。内容を確認して、同意する場合は 1 続いて Enter を押します:
2014102107

Windows/Mac OS X 環境ではお馴染みのセットアップが開始されます:
2014102108

これ以降は基本的に Windows や Mac OS X での作業と変わりありません。Domino サーバーを指定して、ユーザーを指定して、Notes ID ファイルを指定して、パスワードを入力して、・・・という順にセットアップを行っていくだけです。


そして、最終的にセットアップが完了すればノーツクライアントが RHEL/CentOS 上で起動します。次回起動時はメニューから同じ項目を選択すればセットアップを飛ばして起動できます:
2014102109


こうなると今度は、現在 WIndows でしか使えない Domino Designer クライアントや Domino Administrator クライアントも欲しくなる。後者は Web でできないこともないけど、前者は Windows 必須なので。

それにしても IBM Notes って「オフィス」に分類されてるんだ、ふーん。。。

LibreOffice をインストールすると IBM Notes と Office スイートが同じメニューカテゴリに入るのがなんか違和感あるんだよな。。
 2014102110

最近、CentOS ベースのリモートデスクトップ環境を手に入れたので、CentOS で使える各種デスクトップツールを漁っています。

個人的に便利に使っているのが「付箋」ツール。パスワードを書いたりするつもりはないけど、ちょっとしたメモはやはりPCのデスクトップ画面に常に表示されているからこそ便利だったりするわけです。

Windows だと普通にフリーソフトがあるけど、CentOS(GNONE)でも使えないかなあ、と思って調べたら、やはり需要があるのでしょう。KDE ベースの KNotes というツールが見つかりました:


Knotes は KDE 用 PIM(Personal Information Management : 個人情報管理)ツールに含まれています。というわけで、PIM ごと KNotes をインストールします。ターミナルから、以下のコマンドを実行します:
# yum install kdepim

で、X Window のメニューから アクセサリ > KNotes を選択して起動します:
2014101901


起動したら最初に名前(タイトルバーに表示されるもの)を入力します(後でも右クリックメニューから Rename で変更できます):
2014101902


そして付箋の中身を編集して、角をドラッグ&ドロップで移動してサイズを変更するだけです:
2014101903


注意点として、この KNotes は初期状態では自動実行「しません」。なので再起動したり、一度ログアウトしてログインするなどすると消えてしまいます。情報は残っているので、再度明示的に KNotes を起動すれば元に戻りますが、どうせなら自動起動してほしいですよね。

というわけで、最後に KNotes(に限らないけど、アプリケーション全般)を自動実行させる方法を紹介します。まずはメニューから システム > 設定 > 自動起動するアプリ を選択します:
2014101904


「自動起動するアプリの設定」ダイアログが表示されたら「追加」ボタンをクリック:
2014101905


名前は適当に「付箋ツール」などと入力します。そしてコマンドには KNotes のファイルパスである "/usr/bin/knotes" と入力して、「追加」ボタンをクリックします:
2014101906


前の画面に戻ります。ここで「付箋ツール」が追加されたことを確認して「閉じる」をクリックします。これで自動起動の設定が完了しました:
2014101907


一旦ログアウトしてログインし直すか、または再起動して再ログインします。すると KNotes(付箋)は元に戻った状態でデスクトップが表示されます:
2014101908



 

このページのトップヘ