2014年5月13日火曜日

Puppet Enterprise と Puppet Open Sourceの違い

オープンソースなIT自動化ソフトウェアとして有名なpuppetですが、2つのエディションがあるようです。

Puppet Enterprise

  •  Graphical User Interface
  •  Event Inspector - Visualize Infrastructure Changes
  •  Supported Modules
  •  Provisioning - Amazon EC2
  •  Provisioning - Google Compute Engine
  •  Provisioning - VMware VMs
  •  Configuration management - Discovery
  •  Configuration management - User accounts
  •  Configuration management - Operating systems & applications
  •  2,000+ pre-built configurations on Puppet Forge
  •  Orchestration - Task automation
  •  Role-Based Access Control - Now with external authentication support
  •  Unified cross-platform installer of all components
  •  Support  - Option for 24 x 7 x 365
  •  Support  - Defined SLA
  •  Certified by Puppet Labs engineers
  •  Pre-packaged dependencies in one directory
  •  Smooth upgrade and maintenance path
(*)太字はOpen Source版にもある機能を示しています


Puppet Open Source

  •  Provisioning - Amazon EC2
  •  Provisioning - Google Compute Engine
  •  Configuration management - Operating systems & applications
  •  2,000+ pre-built configurations on Puppet Forge


こうして比較してみると、結構Open Source版は機能が劣る印象があります。
Supportがないのはまあ当然としても、GUIとかVMwareのプロビジョニングぐらいはOpenSource版でも欲しい気がします。


ちなみにEnterprise版のお値段ですが10ノードまでは無料。
それ以降は下記のようになってます。

ノード数 Standard Support(1ノードあたり) Premium Support(1ノードあたり)
1-10 Download FREE N/A
11-99 $112 要問い合わせ
100-249 $105 $199
250-499 $99 $135
500-999 $95 $119
1000-2499 $93 $112
2500+ 要問い合わせ 要問い合わせ

Standard Supportでもノード一台あたり100ドル前後ってかなり高い気がしますが、Enterprise版は売れてるんですかね。


参考

2014年5月10日土曜日

TomcatとFirefoxのCache設定

Tomcatなどを使ってWeb開発をしていると、htmlとかwarの修正が、ブラウザ上に反映されなくて悩むことがたまにある。

以前からちょくちょく悩んでは適当に対応していたのだが、この度本格的に困ったので方法を探してみた。

Webを探しても、あまり情報が無かったり、なぜか私の環境では有効でなかったりしたので備忘録としてまとめる。


環境

 OS       Macbook Air 10.8.5 Mountain Lion
 ブラウザ  Firefox 28
 サーバ   Tomcat 7.0.52

Firefoxの設定

  1. ブラウザのアドレスバーにabout:configと入れる。
  2. 「動作保証対象外になります」とメッセージが出るので、「最新の注意を払って使用する」をクリックする。
  3. 「検索」にbrowser.cache.memory.enableを入力する。
  4.  browser.cache.memory.enableが表示されるので、ダブルクリックをして設定値をdisableにする。
  5.  同様にbrowser.cache.memory.enableの値もdisableにする。
  6.  Firefoxを再起動する

Tomcatでデプロイ時にやること


Webを探した限りではデフォルトの設定では特にcache等してないようだった。
ただし、webapp配下にデプロイするwarを置き換えて、tomcatを再起動しただけだと、なぜかwebapp配下に自動unpackされるはずのディレクトリの内容が更新されていなかった。

そのため、warを置き換える前に、自動unpackされるディレクトリを削除しておいた。

例を上げて説明すると、example.warを配置する場合下記の手順で行った。

  1. example.warを作る
  2. <tomcatのホームディレクトリ>/webapp/exampleディレクトリを削除
  3. example.warを<tomcatのホームディレクトリ>/webapp/example.warに配置
  4. tomcatの再起動



今回は、terminalでtomcatを起動してごにょごにょやっているんですが、Eclipseからtomcatを起動した時はここまで更新されない現象に悩まされなかった気がします。
Eclipseさんはなにか特別なことをやってるんだろうか。





2014年4月4日金曜日

java.lang.IllegalStateExceptionの対処法

JavaEE7のRemoteEndpoint.Async.sendText()を連続して呼び出すと、java.lang.IllegalStateExceptionがスローされることがあります。

これは、sendText()の処理が終わる前に、再度sendText()が呼び出されたためです。
sendText()の処理は非同期で行われるために、メソッドが戻ってきたとしてもメッセージ送信が終了している保証はありません。

これを防ぐためには、sendText()の戻り値であるFutre型のオブジェクトのget()を呼び出して、処理が終わるのを待つ必要があります。



 public void sendMessageToBrowser(String message) {
  for (Session s : sessions) {
   Future future = s.getAsyncRemote().sendText(message);
   try {
    future.get();
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (ExecutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

2014年4月1日火曜日

websocketのサンプルコードをJavaEEで書いた

JavaEE7にはwebsocketを実装したパッケージ(javax.websocket)が提供されています。

これを使ったサンプルコードを書いてみました。
ブラウザから入力された数字の数だけ、適当な文字列(数字列)を接続している全ブラウザに表示するコードです。

まずはJava側。Servletクラスとかを継承しなくていいみたいです。
注意が必要なのは、RemoteEndpoint.Async.sendText()はFuture型のオブジェクトを返すということ。つまり、sendText()メソッドの処理は非同期で行われます。

sendText()はその仕様として処理が終わる前に、再び呼び出されるとjava.lang.IllegalStateExceptionを送出します。そのため、for文などを用いて繰り返し、メッセージを送りたい場合はFuture.get()などを用いて、処理が終わるのを待ってから次のメッセージを送るようにします。

import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/endpoint")
public class Main {
    static Set<session> sessions = Collections.synchronizedSet(new HashSet<session>());
    @OnMessage
    public void onMessage(String message) {
        int count = Integer.valueOf(message);
        run(count);
    }

    @OnOpen
    public void open(Session sess) {
        sessions.add(sess);
    }

    @OnClose
    public void close(Session sess) {
        sessions.remove(sess);
    }

    public void sendMessageToBrowser(String message) {
       for (Session s : sessions) {
           Future future = s.getAsyncRemote().sendText(message);
           try {
                   future.get();
           } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
           } catch (ExecutionException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
           }
       }
    }
 
    private void run(int count){
        Random rnd = new Random();
  
        for(int i = 0; i &lt count; i++){
                 String s = String.valueOf(rnd.nextInt());
                sendMessageToBrowser(s);
        }
    } 
}

続いてhtml。

<!DOCTYPE html>
<html>
    <head>
        <title>WebSocketテスト</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="http://code.jquery.com/jquery-1.9.0.js"></script>
        <script type="text/javascript">
            var socket;
            $(document).ready(function(){
             var server="ws://localhost:8080/temporary/endpoint";
                socket = new WebSocket(server);
                
                socket.onmessage = function(message){
                    $('#messageFromServer').append(message.data + "<br/>");
                };

                $('#send').click(function(){
                    var text = $('#msg').val();
                    socket.send(text);
                })

            });
        </script>        
    </head>
    <body>
        <div id="messageFromServer">
        input the integer</div>
        <input id="msg" type="text"/>
        <button id="send">go</button>
    </body>
</html>

参考文献
WebSocketをネタにJava EE 7正式版を試してみる

2014年3月14日金曜日

Mac X 10.8.5(Mountain Lion)のEclipseでJDK7を利用する方法

Mac OS X上のEclipseでJDK7を入れる方法をググると情報が錯綜しているようなので私がやった方法をまとめてみた。

1. まずOracleのサイトからJDKを取得(*)

2. dmgを叩いてインストール。

3. Eclipse->Preference->Java->Installed JREを開き、下記の場所をJRE Homeに指定。

Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/

(*)Apple公式から落とすとの情報もあったが、ファイル名にバージョンの表記がなくよくわからなかったので、Oracleから落とした。

JDKのインストール場所がわからなくって結構困った。

またjava preferences というアプリが、/Utility/Application配下にあり、ここにパス情報が書かれているとの情報が良く出てくるが、最近ではなくなっているようだ。

参考文献。
MacにJDK7をインストールしたからといってAppleのJDK6を消してはいけない

java preferencesがない

2014年3月7日金曜日

Jerseyのサンプルコード

JavaでRestfulなサーバを実装するためのライブラリであるJerseyを触ってみました。
アノテーションを利用することによって、URLとJavaのメソッドの呼び出しを簡単に実装できるようになってます。


import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("sample/{samplePathParam}")
public class Main {
 @Path("get1")
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 public String get1(
   @DefaultValue("2") @QueryParam("testInt") int testInt,
   @DefaultValue("true") @QueryParam("testBoolean") boolean testBoolean,
   @DefaultValue("value") @QueryParam("testString") String testString) {
  return String.valueOf(testInt) + ";" + String.valueOf(testBoolean)
    + ";" + String.valueOf(testString);
 }
 @Path("get2")
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 public String get2(
   @PathParam("samplePathParam") String param) {
  return param;
 }
 @Path("get3/{samplePathParamWithConstraint: [a-z]*}")
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 public String get3(
   @PathParam("samplePathParam") String param1,
   @PathParam("samplePathParamWithConstraint") String param2) {
  return param1 + ":" + param2;
 }
}

これに対して色々アクセスしてみました。
http://localhost:8080/SampleServer/webapi/sample/foo/get1?testInt=10&testBoolean=false&testString=hoge
=>10;false;hoge
get1以下のクエリストリングがjavaの引数に渡されています。
http://localhost:8080/SampleServer/webapi/sample/foo/get2
=>foo
@Path("sample/{samplePathParam}")で指定したsamplePathParamがget2の引数に引き継がれてます。
http://localhost:8080/SampleServer/webapi/sample/foo/get3/bar
=>foo:bar
@Path("sample/{samplePathParam}")で指定したsamplePathParamと@Path("get3/{samplePathParamWithConstraint: [a-z]*}")で指定したsamplePathParamWithConstraintがget3の引数に引き継がれてます。

アノテーションの使い方の詳細は公式ドキュメントがわかりやすいです。

参考文献
Chapter 3. JAX-RS Application, Resources and Sub-Resources

2013年12月15日日曜日

Paizaのオンラインハッカソンに参加してみた

ちょっと前に話題になったpaizaのオンラインハッカソンに参加してみました。

とりあえず言語はjavaを選択。下記のような方針でコードを書きました。

1. 商品の金額データを昇順にソートする。
2. ソート済みのデータに対して先頭と後尾から挟み撃ちで検索をかけ、指定されたキャンペーン金額以下の最大値を検索する。

計算量は1がN(O*logN)で2がO(N)。なので全体としてはN(O*logN)になります。
2の探索はbinary searchを利用すればもう少し早くなりそうですが、どのみち1のソートでO(N*logN)かかるので、手を抜きました。

実際に書いたコードは次のようになります。







import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;


public class Main {

    public static void quickSort(int[] arr, int left, int right){
        if (left <= right) {
            int p = arr[(left+right) / 2];
            int l = left;
            int r = right;
            
            while(l <= r) {
                while(arr[l] < p){ l++; }
                while(arr[r] > p){ r--; }
                
                if (l <= r) {
                    int tmp = arr[l];
                    arr[l] = arr[r];
                    arr[r] = tmp;
                    l++; 
                    r--;
                }
            }
    
            quickSort(arr, left, r);
            quickSort(arr, l, right);
        }
    }
 public static void main(String args[]){

     try {
         BufferedReader br = 
           new BufferedReader(new InputStreamReader(System.in));         

         String nd[] = br.readLine().split(" ");
         int n = Integer.parseInt(nd[0]);
         int d = Integer.parseInt(nd[1]);
         
         int narr[] = new int[n];
         
         int min = Integer.MAX_VALUE;
         for(int i = 0; i < n; i++){
          int a = Integer.parseInt(br.readLine());          
          if(a < min){
           min = a;
          }
          
          narr[i] = a;

         }
         
         quickSort(narr,0,n-1);
         for(int i = 0; i < d; i++){
          
          int a = Integer.parseInt(br.readLine());          
          if(a <= min * 2){
           System.out.println(0);
          }else{
           int start = 0;
           int end = n -1;
           int max = 0;
           while(start < end){
            int sum = narr[start] + narr[end];
            if(sum <= a && sum > max) max = sum;
            
            if(sum == a){

             break;
            }
            if(sum > a){
             end--;
            }else{
             start++;
            }
           }
           System.out.println(max);
            
          }
         }

     } catch (Exception e) {
      e.printStackTrace();
         System.err.println("Error:" + e.getMessage());
     }

 }
}


結果を見ると無事case3まで実行完了できているようでした。

Test case 1 通過 実行時間:0.08 秒
Test case 2 通過 実行時間:0.09 秒
Test case 3 通過 実行時間:0.22 秒

と、クリアしてしまったので、ここで満足しちゃいましたが、この先更に速度を挙げためのアイデアがいくつか考えられます。

1. 探索をbinary searchにする
2. 探索時に一度探索したデータをキャッシュ化して覚えておく。ただしキャンペーン日数が75しかないので、今回のデータセットではあまり効果が薄いかもしれません。

参考文献

1. 「クイックソートのサンプルコード」
http://homepage3.nifty.com/teranet/JavaAlgorithm/QuickSort.html