ジュース

machidaさんから真ん中に保冷剤が入っている飲み物入れ?を貰いました。カワユス

cucumber

cucumberのインストール画面。かわいい。(::)

随時更新。

Macのシンボリックリンク

zshで先頭を大文字で打たないと保管されないのが面倒なので。

% ln -s ~/Sites ~/site
% ln -s ~/Documents ~/doc

こっちの方が良い(via milkcocoa)

% vi ~/.zshrc
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

viで:e ~/siteには効果なし

GAEjがどんなもんかイマイチつかめなかったんですが、やってみて、「最初からそういってくれよ!」と思ったので、過去の自分へのFAQ。

Q. どうやって動くの?
A. Java SE 6とServlet標準(実際はJetty)で動く。Java SE 6自体が過去のバージョンのclassもサポートしてるので大抵動く。あくまでServletが動くだけで勝手なプロセスを動かせるわけじゃないよ。(プロセスやスレッドの生成はできない)

Q. どうやってスケールするの?
A. 高負荷が続くと勝手にサーバインスタンスが増えてデプロイされるらしい。データはBigTable(分散KVS)に保存する。ファイルの書き込みは出来ない。

Q. どうやってアップするの?
A. そのためのクラスがあって、CUIからはラッパーシェルスクリプト、antタスク、GUIからはEclipse Pluginがある。どこのサーバーにアップするかとかそういうのを気にする必要は無い。

Q. 何をアップすればいいの?
A. app-engine.xmlという固有の設定ファイルを含めたWAR標準に則ったディレクトリをアップすればいい。(WARのアーカイブはまだサポートされてないらしい)

Q. 独自ドメイン使えるの?
A. 使える。

Q. じゃあすごい良さそうじゃん
A. だから散々そうだっつってんだろボケ!

GAE(がえ)

% tree hellogaej                                
hellogaej
|-- build.xml
|-- html
|-- src
|   |-- META-INF
|   |-- WEB-INF
|   `-- hellogaej
|       `-- HelloGAEJServlet.java
`-- war
    `-- WEB-INF
        |-- appengine-web.xml
        |-- classes
        |-- lib
        `-- web.xml
% vi hellogaej/src/hellogaej/HelloGAEJServlet.java
package hellogaej;

import java.io.IOException;
import javax.servlet.http.*;

public class HelloGAEJServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("Hello, GAEj!");
    }
}
% vi hellogaej/war/WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">
  <display-name>Hello Google App Engine for Java</display-name>

  <servlet>  
    <servlet-name>hellogaej</servlet-name>
    <servlet-class>hellogaej.HelloGAEJServlet</servlet-class>
  </servlet>  

  <servlet-mapping>
    <servlet-name>hellogaej</servlet-name>
    <url-pattern>/hellogaej</url-pattern>
  </servlet-mapping>
</web-app>

GAEj固有の設定ファイル。アプリ名やバージョンを書くそうです。

% vi hellogaej/war/WEB-INF/appengine-web.xml
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>hellogaej</application>
  <version>1</version>
</appengine-web-app>

App Engine SDKに含まれているdev_appserver.shを使って開発サーバーを起動できる。${appengine.sdk}/config/user/ant-macros.xmlに便利なantタスクがあるのでそれを利用するとなお便利。

% vi hellogaej/build.xml
<project name="hellogaej" default="war">
  <property name="appengine.sdk" location="/usr/local/appengine-java-sdk-1.2.6"/>  <fail message="Please define the appengine.sdk property to point to your SDK directory">
    <condition>
      <not> <and>
          <isset property="appengine.sdk"/>
          <available file="${appengine.sdk}/config/user/ant-macros.xml"/>
      </and> </not>
    </condition>
  </fail>
  <import file="${appengine.sdk}/config/user/ant-macros.xml"/>
  <property name="debug.port" value="5005"/>
  <property name="http.port" value="8080"/>
  <property name="log.file" value="app.log"/>
  <property name="log.days" value="2"/>
  <property name="war.dir" location="war"/>
  <target name="war" depends="enhance"
          description="Assemble the application directory">
    <mkdir dir="${war.dir}/WEB-INF"/>
    <copy todir="${war.dir}">
      <fileset dir="html">
        <exclude name="**/.svn/**"/>
        <exclude name="**/*~"/>
      </fileset>
    </copy>
    <copy todir="${war.dir}/WEB-INF">
      <fileset dir="src/WEB-INF">
        <include name="*.xml"/>
      </fileset>
    </copy>
    <enhance_war war="${war.dir}"/>
  </target>

  <target name="enhance" depends="compile"
          description="Enhance the classes after compilation">
    <enhance_war war="${war.dir}"/>
  </target>

  <target name="compile"
          description="Compile the application servlet code">
    <mkdir dir="${war.dir}/WEB-INF/classes"/>
    <mkdir dir="${war.dir}/WEB-INF/lib"/>
    <javac srcdir="src" destdir="${war.dir}/WEB-INF/classes">
      <classpath>
        <fileset dir="${appengine.sdk}/lib/user">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${appengine.sdk}/lib/shared">
          <include name="*.jar"/>
        </fileset>
      </classpath>
    </javac>
  </target>

  <target name="clean"
          description="Force a clean slate to rebuild">
    <delete dir="${war.dir}"/>
  </target>

  <target name="runserver" depends="war"
          description="Run the dev_appserver">
    <dev_appserver war="${war.dir}" port="${http.port}"/>
  </target>

  <target name="dev_appserver" depends="runserver"/>

  <target name="debug" depends="war"
          description="Launches dev_appserver with remote debugging enabled">
    <echo message="Launching dev_appserver on Web port ${http.port}, Java remote debug port ${debug.port}"/>
    <dev_appserver war="${war.dir}" port="${http.port}">
      <options>
        <arg value="--jvm_flag=-Xdebug"/>
        <arg value="--jvm_flag=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug.port}"/>
      </options>
    </dev_appserver>
  </target>

  <target name="update" depends="war"
          description="Uploads the application, including indexes">
    <appcfg action="update" war="${war.dir}"/>
  </target>

  <target name="update_indexes" depends="war"
          description="Uploads only the application's indexes">
    <appcfg action="update_indexes" war="${war.dir}"/>
  </target>

  <target name="rollback" depends="war"
          description="Rolls back any in-progress application update">
    <appcfg action="rollback" war="${war.dir}"/>
  </target>

  <target name="request_logs"
          description="Downloads the application's logs">
    <appcfg action="request_logs" war="${war.dir}">
      <options>
        <arg value="--num_days=${log.days}"/>
      </options>
      <args>
        <arg value="${log.file}"/>
      </args>
    </appcfg>
  </target>
</project>
% ant dev_appserver
http://localhost:8080/hellogaej

面倒臭くて死にそうでしたが、どの言語もJREとServlet上で動くので知っとかないとと思って。

Dock

何か最近、いつのまにか空のXが立ち上がってることが多いんだけどなんだろうね。

tomcatインストール

$ wget http://ftp.kddilabs.jp/infosystems/apache/tomcat/tomcat-6/v6.0.20/bin/apache-tomcat-6.0.20.zip
$ unzip apache-tomcat-6.0.20.zip
$ mv apache-tomcat-6.0.20 /usr/local/
$ vi ~/.zshrc
export JAVA_HOME=/Library/Java/Home
export CATALINA_HOME=/usr/local/apache-tomcat-6.0.20
export CLASSPATH=.:$CATALINA_HOME/lib/servlet-api.jar:$CATALINA_HOME/lib/jsp-api.jar
$ source ~/.zshrc
$ sudo /usr/local/apache-tomcat-6.0.20/bin/startup.sh

Hello, Servlet!

$ cd /usr/local/apache-tomcat-6.0.20/webapps
$ mkdir -p hello-servlet/src hello-servlet/WEB-INF/classes
$ cd hello-servlet/src
$ vi HelloServlet.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloServlet extends HttpServlet {
    public void service(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/plain");
        response.getWriter().println("Hello, Servlet!");
    }
}
$ javac HelloServlet.java
$ mv HelloServlet.class ../WEB-INF/classes

デプロイメントディスクリプタを書く。

$ vi /usr/local/apache-tomcat-6.0.20/conf/server.xml
(...)
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">   
        <Context path="/hello-servlet" docBase="hello-servlet" debug="0" reloadable="true" crossContext="true" />
(...)
      </Host>
(...)
$ vi /usr/local/apache-tomcat-6.0.20/webapps/hello-servlet/WEB-INF/web.xml
<?xml version="1.0" ?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  <servlet>  
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>HelloServlet</servlet-class>
  </servlet>  
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/HelloServlet</url-pattern>
  </servlet-mapping>
</web-app>
HelloServlet

sudo port install tomcat6がこけるのが謎。

Win32API、C、gccで1時間でテトリスを作る実況動画。手際がよくて見てて楽しいです。特に最後に作ったテトリスのコードをちょっと変えて見せることで見ている人にわかりやすくプログラミングの面白さを伝えていて素晴らしい動画でした。

Macにはjavaが最初から入ってるそうです。

% java -version     
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03-219)
Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02-90, mixed mode)

オプションのハイフン一つなんですなあ。

% vi HelloWorld.java
public class HelloWorld {
    public static void main(String args []) {
        System.out.println("Hello, World!");
    }
}
% javac HelloWorld.java   
% java HelloWorld 
Hello, World!

うん。

会社の無線LANルーターが結構落ちる。

インターリンクの固定IP8を使っているのでUnnumberd IPという機能が必要みたい。(よくわかってない)

COREGAのCG-WLBARGPXBという無線LANルーターはUnnumberd IP + Private IPというのに対応しているらしく、これを使っているんですが、COREGAのルーターはある程度接続が多い環境では結構落ちる。

corega CG-WLBARGPXB
  • corega CG-WLBARGPXB
  • コレガ
  • コレガ
  • 定価:¥ 5,565
  • 新品価格:¥ 3,800
  • ASIN:B000MQCD6Q

価格.comで評判良く、Unnumberd IPに対応してるというBUFFALOのWZR-AGL300NHを買ってみた。家でしばらく使ったけど切れないので会社でも購入してみた。

BUFFALO AirStation NFINITI Draft11n対応 11g&b 無線LANブロードバンドルータ WZR2-G300N

ところが、こっちのはUnnumberd IPには対応していてもPrivate IPには対応していないらしく、社内のサーバーにグローバルIPだけしか割り当てられない。(現在はCG-WLBARGPXBで社内サーバーにグローバルとローカルIP両方割り当てている)

手間はかけられないのでPCルーターを作ることは避けたい。どなたか接続人数が10人程度で落ちなくて、Unnumberd IP + Private IPに対応している無線LANルーターをご存じの方は教えていただけるとありがたいです。

教えていただいた方には裸族の二世帯住宅をお贈りいたします。

センチュリー 裸族の二世帯住宅NAS LAN接続HDDケース CRNS35NAS

会社の状態。

高いところに置けば遠くまで届くかな?

Private IP割り当てられないので使われてないヤツ。

夏を乗り切ったVSDLモデム。