Wicket on dotCloud

なんかWicket ( http://wicket.apache.org/ ) がお手軽ウェブフレームワークらしいので触ってみることにしました。ついでにdotCloudとかいう最近有名なアレの上に乗っけてみることにしました。

ステップ0. dotCloudデプロイ準備

http://docs.dotcloud.com/firststeps/install/ 参考に適当に

$ pip install dotcloud
$ dotcloud setup

ステップ1. Wicketのプロジェクトの作成

プロジェクトはmavenで作成します。しかしmavenのプロジェクト作成コマンドはいつもいつもめんどくさくて覚えてられないですね。Wicketさんはその辺のフォローもしっかりしています。Create a Wicket Quickstart | Apache Wicketで作りたいプロジェクトのグループIDとアーティファクトIDを入力すれば実行すべきコマンドが出てきます。

$ mvn archetype:generate -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5.3 -DgroupId=org.hogel -DartifactId=wicket-test -DarchetypeRepository=https://repository.apache.org/ -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] Archetype defined by properties
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.547s
[INFO] Finished at: Sat Jan 07 22:58:38 JST 2012
[INFO] Final Memory: 7M/133M
[INFO] ------------------------------------------------------------------------

簡単にできました。

$ cd wicket-test
$ mvn jetty:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building quickstart 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
いろいろたくさん...
INFO  - WebApplication             - [wicket.wicket-test] Started Wicket version 1.5.3 in DEVELOPMENT mode
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
2012-01-07 22:59:56.017:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080 STARTING
2012-01-07 22:59:56.376:INFO:oejs.AbstractConnector:Started SslSocketConnector@0.0.0.0:8443 STARTING
[INFO] Started Jetty Server

起動しました。アクセスしてみましょう→ http://localhost:8080/

コマンド叩いただけなのになんかできてて最近のウェブフレームワークっぽいですね。中身はあとで触っていきましょう。

ステップ2. DEPLOYMENTモードにする

mvn jetty:runしたときにこんな表示をしていましたね。

INFO  - WebApplication             - [wicket.wicket-test] Started Wicket version 1.5.3 in DEVELOPMENT mode
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************

上記メッセージの通り、WicketApplication.javaにWicketApplication#getConfigurationType()を追加します。

package org.hogel;

import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.protocol.http.WebApplication;

/**
 * Application object for your web application. If you want to run this application without deploying, run the Start class.
 *
 * @see org.hogel.Start#main(String[])
 */
public class WicketApplication extends WebApplication
{
    /**
     * @see org.apache.wicket.Application#getHomePage()
     */
    @Override
    public Class<HomePage> getHomePage()
    {
        return HomePage.class;
    }

    /**
     * @see org.apache.wicket.Application#init()
     */
    @Override
    public void init()
    {
        super.init();

        // add your configuration here
    }

    @Override
    public RuntimeConfigurationType getConfigurationType() {
        return RuntimeConfigurationType.DEPLOYMENT;
    }
}

ステップ3. パッケージング

mavenWicketプロジェクトをwarファイルにパッケージング。

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building quickstart 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
色々...

wicket-test/target/wicket-test-1.0-SNAPSHOT.warができている。おしまい。

ステップ4. デプロイ

http://docs.dotcloud.com/services/java/を参考に先のwarファイルをデプロイしてみる。

dotCloud上にwickettestというアプリケーションを作成する。

$ dotcloud create wickettest
Created application "wickettest"

dotcloudディレクトリを作ってdotcloud用のファイルをまとめる。

$ mkdir dotcloud
$ cp target/wicket-test-1.0-SNAPSHOT.war dotcloud/ROOT.war

dotcloud/dotcloud.ymlに以下の内容を記述

www:
  type: java

デプロイ。

$ dotcloud push wickettest dotcloud

http://wickettest-hogelog.dotcloud.com/

デプロイ完了。うーん便利な時代ですねー。

websocketで遊んでみた powered by Jetty 8

とりあえずベタベタにチャット的なものを。

ソースコードhttps://github.com/hogelog/chatty に。

Windowsで動くWebSocketサーバをサクッと書くにはJavaでJetty使うのが一番楽だなあということがよくわかりました。rubyのアレとかpythonのソレとかこれとか、だいたいlibeventやらなんらかのネイティブライブラリを使っているので面倒。JettyでWebSocket使うには、pom.xmlを適当に仕上げて*1、ソース書いて、あとは

 $ mvn jetty:run

と叩くだけで依存するライブラリ落としてきて(ネイティブライブラリのビルドとかが始まることなしに)普通にサーバが動き始める。良い。

pom.xmlにjetty-websocketを記述。

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-websocket</artifactId>
            <version>8.1.0.RC1</version>
        </dependency>
@WebServlet("/chatty")
public class ChattyServlet extends WebSocketServlet {
    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
        return new ChattyWebSocket();
    }
}
public class ChattyWebSocket implements WebSocket.OnTextMessage {
    public void onOpen(Connection connection);
    public void onClose(int closeCode, String message);
    public void onMessage(String data);
}

こんな感じで書く。WebSocket.OnTextMessage以外にもOnBinaryMessageとかもあるし普通に使いやすそう。

http://download.eclipse.org/jetty/stable-8/apidocs/org/eclipse/jetty/websocket/WebSocket.html

*1:それが面倒なんだろうけど

Java7触ってみる(2) 削除済みファイルの読み書き

もしかしてできるようになっているのではと思ったらできるようになっていた喜ばしい。6まででやる方法あったんだろか? TrueZIPとか使えばできるかもしれない。

package org.hogel.NioTest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;

public class NioTest {
    /**
     * 通るテスト
     */
    @Test
    public void 削除済みのファイルへの読み書き_nio() throws Exception {
        Path path = Paths.get("tmp");
        try (BufferedWriter writer = Files.newBufferedWriter(path, Charset.defaultCharset(), StandardOpenOption.CREATE)) {
            try (BufferedReader reader = Files.newBufferedReader(path, Charset.defaultCharset())) {
                writer.write("ほげ");
                assertThat(Files.deleteIfExists(path), is(true));
                assertThat(Files.exists(path), is(false));
                writer.write("ふが");
                writer.flush();
                String line = reader.readLine();
                assertThat(line, is("ほげふが"));
            }
        }
    }

    /**
     * 通らないテスト
     */
    @Test
    public void 削除済みのファイルへの読み書き_legacy() throws Exception {
        File file = new File("tmp");
        try (Writer writer = new FileWriter(file)) {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                writer.write("ほげ");
                assertThat(file.delete(), is(true)); // ここで失敗する
                assertThat(file.exists(), is(false));
                writer.write("ふが");
                writer.flush();
                String line = reader.readLine();
                assertThat(line, is("ほげふが"));
            }
        }
    }
}

Java7触ってみる(1) ZipFS

package org.hogel.ArchiveTest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class ZipTest {
    @Test
    public void zipfsのテスト() throws Exception {
        URI zipfile = URI.create("jar:file:/tmp/zipfs-test.zip");
        Map<String, String> env = new HashMap<>();

        // ZIPファイルを新規作成、ZIPエントリ名のエンコーディングはMS932(Shift-JIS)に
        env.put("create", "true");
        env.put("encoding", "MS932");
        try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, env)) {
            // ほげ.txtファイルをZIPファイル内に作成
            Files.write(zipfs.getPath("ほげ.txt"), "ほげ".getBytes("MS932"), StandardOpenOption.CREATE);
        }

        // ZIPエントリほげ.txtというエントリ名がMS932(Shift−JIS)であることを確認
        byte[] zipdata = Files.readAllBytes(Paths.get("/tmp/zipfs-test.zip"));
        assertThat(new String(zipdata, "MS932").contains("ほげ.txt"), is(true));

        // 既存のZIPファイルの読み込みテスト
        env.put("create", "false");
        try (FileSystem zipfs = FileSystems.newFileSystem(zipfile, env)) {
            // ZIPファイル内のほげ.txtファイルを確認
            assertThat(new String(Files.readAllBytes(zipfs.getPath("ほげ.txt")), "MS932"), is("ほげ"));
        }
    }
}

ZIPへの追記、パス名のエンコーディング指定とかが標準ライブラリでできる。Java6でやりたければTrueZIPかな。まあJava7、ボチボチ細かく便利になっていていいですね。

pythonでシンプルなカメラアプリケーション

pythonだけでシンプルに。ライブラリは

を使用。使ったカメラはhttp://www.logitech.com/ja-jp/435/3055

カメラから取ってくる画像バッファがなぜかBGRになっている(?)のでBGR->RGBに変換。使うカメラによっては色がおかしくなるかも。よくわからん。

Google Chromeのabout:flags 「Enable experimental WebUI」で変わるもの

http://codereview.chromium.org/7919028
今のところブックマークの編集がネイティブダイアログじゃなくなるぐらいだろうか。

ネイティブダイアログをブラウザの機能から排除していくことでプラットフォーム間のUIの違いとかを吸収していこうとしてるのかな。

LogicoolトラックボールTM-150のUniversal ScrollがFirefoxで全然スクロールできない件について。

なんか色々対応していないのかなんなのか、←↓↑→キーをFirefoxに送ることで擬似的にスクロールしているせいでやたら遅いらしい。根本的な解決方法とか調べるのが面倒。とりあえずKeySnailがインストールしてあるので.keysnail.jsに以下の設定を追加、↓↑キーをフックしてスクロール量を増やすことでとりあえず対応。

key.setViewKey('<up>', function () {
    var win = window.content;
    var x = win.scrollX;
    var y = win.scrollY;
    var toy = y - 40;
    win.scrollTo(x, toy);
}, 'もっとup');
key.setViewKey('<down>', function () {
    var win = window.content;
    var x = win.scrollX;
    var y = win.scrollY;
    var toy = y + 40;
    win.scrollTo(x, toy);
}, 'もっとdown');

40という数字は適当。大きくすれば大きくスクロールするようになる。

test