<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sinsengumi血風録</title>
	<atom:link href="http://sinsengumi.net/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://sinsengumi.net/blog</link>
	<description>プログラムに関して、会社や家で勉強したことを忘れないように備忘録として書き連ねています。</description>
	<lastBuildDate>Sat, 14 Apr 2012 07:43:38 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>HttpServletRequestWrapperを使って、HTTPリクエストを改変する</title>
		<link>http://sinsengumi.net/blog/2012/04/httpservletrequestwrapper%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%80%81http%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%82%92%e6%94%b9%e5%a4%89%e3%81%99%e3%82%8b/</link>
		<comments>http://sinsengumi.net/blog/2012/04/httpservletrequestwrapper%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%80%81http%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%82%92%e6%94%b9%e5%a4%89%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Sat, 14 Apr 2012 07:42:40 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Servlet]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=548</guid>
		<description><![CDATA[OpenAMは、認証済のユーザー情報をHTTPリクエストヘッダーに載せてくれるんですが、Servletでそれってどうやって実現してるのかなーと思って、調べたら HttpServletRequestWrapper クラスを [...]]]></description>
			<content:encoded><![CDATA[<p>OpenAMは、認証済のユーザー情報をHTTPリクエストヘッダーに載せてくれるんですが、Servletでそれってどうやって実現してるのかなーと思って、調べたら <code>HttpServletRequestWrapper</code> クラスを使うようです。</p>
<p>使い方ですが、<code>HttpServletRequestWrapper</code> は、HttpServletRequestインタフェースを実装しているので、HttpServletRequestインタフェースのメソッドをオーバーライドして独自の実装を定義します。<br />
<a href="http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/javax/servlet/http/HttpServletRequestWrapper.html" target="_blank">http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/javax/servlet/http/HttpServletRequestWrapper.html</a></p>
<p>今は、すべてのリクエストのヘッダーに情報を付与しようとしているので、getHeader辺りをオーバーライドします。</p>
<pre>
package org.sample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class HeaderAddedHttpServletRequest extends HttpServletRequestWrapper {

    private Map&lt;String, String&gt; addHeaders;

    public HeaderAddedHttpServletRequest(HttpServletRequest request, Map&lt;String, String&gt; addHeaders) {
        super(request);

        if (addHeaders == null) {
            this.addHeaders = new HashMap&lt;String, String&gt;();
        } else {
            this.addHeaders = addHeaders;
        }
    }

    @Override
    public String getHeader(String name) {
        String header = super.getHeader(name);
        if (header != null) {
            return header;
        }

        header = addHeaders.get(name);
        if (header != null) {
            return header;
        }

        return null;
    }

    @Override
    public Enumeration&lt;String&gt; getHeaderNames() {
        List&lt;String&gt; newHeaderNames = new ArrayList&lt;String&gt;();

        Enumeration&lt;String&gt; currentHeaderNames = super.getHeaderNames();
        while (currentHeaderNames.hasMoreElements()) {
            newHeaderNames.add(currentHeaderNames.nextElement());
        }

        for (Entry&lt;String, String&gt; e : addHeaders.entrySet()) {
            newHeaderNames.add(e.getKey());
        }

        return Collections.enumeration(newHeaderNames);
    }
}
</pre>
<p>で、すべてのリクエストがこのWrapperクラスを使うようにFilterを定義します。</p>
<pre>
package org.sample;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter(&quot;/*&quot;)
public class AddHeaderFilter implements Filter {

    @Override
    public void init(FilterConfig fConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        Map&lt;String, String&gt; addHeaders = new HashMap&lt;String, String&gt;();
        addHeaders.put(&quot;X-USER-ID&quot;, &quot;HIJIKATA&quot;);
        addHeaders.put(&quot;X-USER-NAME&quot;, &quot;土方歳三&quot;);

        chain.doFilter(new HeaderAddedHttpServletRequest((HttpServletRequest) request, addHeaders), response);
    }
}
</pre>
<p>これで、HTTPリクエストが飛んできたら自動でヘッダーが付与サれてます。</p>
<pre>
package org.sample;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(&quot;/SampleServlet&quot;)
public class SampleServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        Enumeration&lt;String&gt; headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);

            System.out.println(headerName + &quot;=&quot; + headerValue);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }
}
</pre>
<pre>
host=localhost:8080
connection=keep-alive
user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.152 Safari/535.19
accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-encoding=gzip,deflate,sdch
accept-language=ja,en-US;q=0.8,en;q=0.6
accept-charset=Shift_JIS,utf-8;q=0.7,*;q=0.3
X-USER-ID=HIJIKATA
X-USER-NAME=土方歳三
</pre>
<p>同様の事はレスポンスでもできます。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2012/04/httpservletrequestwrapper%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%80%81http%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%82%92%e6%94%b9%e5%a4%89%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>シンプルな HTTP Server 書いた</title>
		<link>http://sinsengumi.net/blog/2012/03/%e3%82%b7%e3%83%b3%e3%83%97%e3%83%ab%e3%81%aa-http-server-%e6%9b%b8%e3%81%84%e3%81%9f/</link>
		<comments>http://sinsengumi.net/blog/2012/03/%e3%82%b7%e3%83%b3%e3%83%97%e3%83%ab%e3%81%aa-http-server-%e6%9b%b8%e3%81%84%e3%81%9f/#comments</comments>
		<pubDate>Sat, 31 Mar 2012 06:40:14 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Socket]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=541</guid>
		<description><![CDATA[以前の記事の続きということで、シンプルな HTTP Server を書いた。 classファイル一つで動くというお手軽サーバー。マルチスレッド？自分しか使わないからいいんですよ。 お手軽に使いたいのでデフォルトパッケージ [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sinsengumi.net/blog/2012/03/socket-%e3%81%ae%e5%8b%89%e5%bc%b7%e3%81%ae%e3%81%9f%e3%82%81%e3%81%ab%e3%82%a8%e3%82%b3%e3%83%bc%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e6%9b%b8%e3%81%84%e3%81%9f/" title="Socket の勉強のためにエコーサーバー書いた">以前の記事</a>の続きということで、シンプルな HTTP Server を書いた。</p>
<p>classファイル一つで動くというお手軽サーバー。マルチスレッド？自分しか使わないからいいんですよ。<br />
お手軽に使いたいのでデフォルトパッケージ。</p>
<pre>
java SimpleHttpServer "C:\htdocs" 81
</pre>
<pre>
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class SimpleHttpServer {

    private static String requestPath;

    private static Map&lt;String, String&gt; CONTENT_TYPES = new HashMap&lt;String, String&gt;();

    static {
        CONTENT_TYPES.put(&quot;html&quot;, &quot;text/html&quot;);
        CONTENT_TYPES.put(&quot;htm&quot;, &quot;text/html&quot;);
        CONTENT_TYPES.put(&quot;css&quot;, &quot;text/css&quot;);
        CONTENT_TYPES.put(&quot;js&quot;, &quot;text/javascript&quot;);
        CONTENT_TYPES.put(&quot;jpg&quot;, &quot;image/jpeg&quot;);
        CONTENT_TYPES.put(&quot;jpeg&quot;, &quot;image/jpeg&quot;);
        CONTENT_TYPES.put(&quot;png&quot;, &quot;image/png&quot;);
        CONTENT_TYPES.put(&quot;gif&quot;, &quot;image/gif&quot;);
        CONTENT_TYPES.put(&quot;pdf&quot;, &quot;application/pdf&quot;);
        CONTENT_TYPES.put(&quot;txt&quot;, &quot;text/plain&quot;);
        CONTENT_TYPES.put(&quot;xml&quot;, &quot;text/xml&quot;);
        CONTENT_TYPES.put(&quot;zip&quot;, &quot;application/zip&quot;);
        CONTENT_TYPES.put(&quot;exe&quot;, &quot;application/octet-stream&quot;);
    }

    public static void main(String[] args) throws IOException {
        String documentRoot = args[0];
        int port = Integer.parseInt(args[1]);

        ServerSocket server = new ServerSocket(port);

        while (true) {
            Socket client = server.accept();

            // HTTPリクエストを出力
            outputRequest(client);

            // HTTPレスポンスを出力
            outputResponse(client, documentRoot);
        }
    }

    private static void outputRequest(Socket client) throws IOException {
        System.out.println(&quot;------------------------------------------&quot;);

        BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));

        // 1行目からリクエストパスを取得しておく（/でアクセスされた場合はindex.htmlを表示）
        String inline = br.readLine();
        requestPath = inline.split(&quot; &quot;)[1];
        if (requestPath.endsWith(&quot;/&quot;)) {
            requestPath += &quot;index.html&quot;;
        }

        while (br.ready() &amp;&amp; inline != null) {
            System.out.println(inline);
            inline = br.readLine();
        }

        System.out.println(&quot;------------------------------------------&quot;);
    }

    private static void outputResponse(Socket client, String documentRoot) throws IOException {
        PrintStream ps = new PrintStream(client.getOutputStream());

        String responseFile = documentRoot + requestPath;
        File file = new File(responseFile);

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);

            // ヘッダー出力
            int bodyLength = (int) file.length();
            ps.println(&quot;HTTP/1.1 200 OK&quot;);
            ps.println(&quot;Content-Length: &quot; + bodyLength);
            ps.println(&quot;Content-Type: &quot; + getContentType(file));
            ps.println(&quot;&quot;);

            // ボディ出力
            byte buf[] = new byte[bodyLength];

            fis.read(buf);
            ps.write(buf, 0, bodyLength);
            ps.flush();
        } catch (FileNotFoundException e) {
            // ヘッダー出力
            ps.println(&quot;HTTP/1.1 404 Not Found&quot;);
            ps.println(&quot;&quot;);
            ps.println(&quot;&lt;h1&gt;指定されたファイルは存在しません。&lt;/h1&gt;&quot;);
        } finally {
            if (fis != null) {
                fis.close();
            }
        }

        ps.close();
    }

    private static String getContentType(File file) {
        String extension = getExtension(file);

        String contentType = CONTENT_TYPES.get(extension);

        if (contentType == null) {
            return &quot;text/html&quot;;
        } else {
            return contentType;
        }
    }

    private static String getExtension(File file) {
        String path = file.getPath();
        int lastDotPosition = path.lastIndexOf(&quot;.&quot;);

        String extension = null;
        if (lastDotPosition == -1) {
            extension = &quot;&quot;;
        } else {
            extension = path.substring(lastDotPosition + 1).toLowerCase();
        }

        return extension;
    }
}
</pre>
<p>コードはGistにもペタリ。<br />
<a href="https://gist.github.com/2260004" target="_blank">https://gist.github.com/2260004</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2012/03/%e3%82%b7%e3%83%b3%e3%83%97%e3%83%ab%e3%81%aa-http-server-%e6%9b%b8%e3%81%84%e3%81%9f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Socket の勉強のためにエコーサーバー書いた</title>
		<link>http://sinsengumi.net/blog/2012/03/socket-%e3%81%ae%e5%8b%89%e5%bc%b7%e3%81%ae%e3%81%9f%e3%82%81%e3%81%ab%e3%82%a8%e3%82%b3%e3%83%bc%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e6%9b%b8%e3%81%84%e3%81%9f/</link>
		<comments>http://sinsengumi.net/blog/2012/03/socket-%e3%81%ae%e5%8b%89%e5%bc%b7%e3%81%ae%e3%81%9f%e3%82%81%e3%81%ab%e3%82%a8%e3%82%b3%e3%83%bc%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e6%9b%b8%e3%81%84%e3%81%9f/#comments</comments>
		<pubDate>Wed, 21 Mar 2012 05:05:17 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Socket]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=533</guid>
		<description><![CDATA[前々から、Jarひとつで動くHTTPサーバーを書いてみたいと思っていて（既にたくさんあると思うけど）、それには Socket でがちゃがちゃしないといけないとの事だったので、重い腰を上げて Socket の勉強をしてみた [...]]]></description>
			<content:encoded><![CDATA[<p>前々から、Jarひとつで動くHTTPサーバーを書いてみたいと思っていて（既にたくさんあると思うけど）、それには Socket でがちゃがちゃしないといけないとの事だったので、重い腰を上げて Socket の勉強をしてみた。</p>
<p>とりあえず、リクエストされた文字列をそのまま返すだけのエコーサーバーを書いてみた。<br />
一応、マルチスレッド対応。</p>
<p><strong>Server</strong></p>
<pre>
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class EchoServer {

    public static void main(String[] args) throws IOException {

        ServerSocket server = new ServerSocket(5000);

        // クライアントからの接続を待ち受ける
        while (true) {
            Socket client = server.accept();

            new Thread(new EchoServer().new EchoThread(client)).start();
        }
    }

    class EchoThread implements Runnable {

        Socket client;

        public EchoThread(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            echo(client);
        }

        private void echo(Socket client) {
            System.out.println(&quot;処理開始&quot;);

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
            }

            System.out.println(&quot;接続中 : &quot; + client.getRemoteSocketAddress());

            try {
                InputStream in = client.getInputStream();
                OutputStream out = client.getOutputStream();

                int recvByte;
                while ((recvByte = in.read()) != -1) {
                    out.write(recvByte);
                }
            } catch (IOException e) {
                System.err.println(e);
            } finally {
                closeQuietly(client);
            }

            System.out.println(&quot;処理終了&quot;);
        }

        private void closeQuietly(Socket socket) {
            try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                // ignore
            }
        }
    }
}
</pre>
<p><strong>Client</strong></p>
<pre>
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class EchoClient {

    public static void main(String[] args) throws IOException {

        Socket socket = new Socket(&quot;localhost&quot;, 5000);
        System.out.println(&quot;サーバとの接続を確立 : &quot; + socket.getLocalPort());

        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();

        byte[] data = args[0].getBytes();
        out.write(data);
        System.out.println(&quot;送信 : &quot; + new String(data));

        int i = 0;
        byte[] output = new byte[data.length];
        int recvByte;
        while ((recvByte = in.read()) != -1) {
            output[i++] = (byte) recvByte;

            if (i &gt;= data.length) {
                break;
            }
        }

        System.out.println(&quot;受信 : &quot; + new String(output));

        socket.close();
    }
}
</pre>
<p>バイトの読み書きを1バイトずつやってるので、あまり効率的ではないんだろうな。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2012/03/socket-%e3%81%ae%e5%8b%89%e5%bc%b7%e3%81%ae%e3%81%9f%e3%82%81%e3%81%ab%e3%82%a8%e3%82%b3%e3%83%bc%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e6%9b%b8%e3%81%84%e3%81%9f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenAM(旧OpenSSO)でシングルサインオンをしてみる</title>
		<link>http://sinsengumi.net/blog/2012/03/openam%e6%97%a7opensso%e3%81%a7%e3%82%b7%e3%83%b3%e3%82%b0%e3%83%ab%e3%82%b5%e3%82%a4%e3%83%b3%e3%82%aa%e3%83%b3%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/</link>
		<comments>http://sinsengumi.net/blog/2012/03/openam%e6%97%a7opensso%e3%81%a7%e3%82%b7%e3%83%b3%e3%82%b0%e3%83%ab%e3%82%b5%e3%82%a4%e3%83%b3%e3%82%aa%e3%83%b3%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/#comments</comments>
		<pubDate>Wed, 14 Mar 2012 04:20:52 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[その他]]></category>
		<category><![CDATA[CDSSO]]></category>
		<category><![CDATA[OpenAM]]></category>
		<category><![CDATA[OpenSSO]]></category>
		<category><![CDATA[SSO]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=486</guid>
		<description><![CDATA[やりたいことは、クロスドメイン（CDSSO）でシングルサインオンを実現し、ユーザーを識別（認可）して、アクセスできるURLを制限したい、というもの。 SSO製品は色々あるようですが、一番とっつきやすそうなOpenAMで試 [...]]]></description>
			<content:encoded><![CDATA[<p>やりたいことは、クロスドメイン（CDSSO）でシングルサインオンを実現し、ユーザーを識別（認可）して、アクセスできるURLを制限したい、というもの。<br />
SSO製品は色々あるようですが、一番とっつきやすそうなOpenAMで試す。<br />
SSOエージェントなど、独特のSSO用語は以下のページがとてもわかり易いです。<br />
<a href="http://dev.ariel-networks.com/column/tech/opensso/" target="_blank">http://dev.ariel-networks.com/column/tech/opensso/</a></p>
<h3>前提</h3>
<p>SSOサーバーとSSOエージェントは別マシン（同じマシンで実行した（もちろんポートを変えて）が上手くいかなかった為）</p>
<ul>
<li>SSOサーバーのホスト(10.29.56.64) ： <strong>sso.server.com</strong></li>
<li>SSOエージェントのホスト(10.29.55.56) ： <strong>sso.agent.com</strong></li>
</ul>
<p>SSOはCookieを用いて、SSO Tokenをやり取りするので、localhostなどでアクセスして設定を行なってしまうと、Cookieのドメイン属性がうまく設定できず、動かない可能性がある。<br />
そのため、設定を行う場合は必ずFQDNでアクセスする。<br />
試しにやる場合は、hostsファイルを編集するのが一番楽かと思います。</p>
<p><strong>hosts</strong></p>
<pre>
10.29.56.64  sso.server.com
10.29.55.56  sso.agent.com
</pre>
<p>なお、このhosts設定はSSOサーバーのマシン、SSOエージェントのマシン<strong>両方</strong>に設定しておく必要がある（どちらもそれぞれのホストを見に行く必要があるため）</p>
<h3>環境</h3>
<ul>
<li>Tomcat 6.0.35（SSOサーバーマシン用）<br />
TOMCAT_HOME=C:\Program Files\apache-tomcat-6.0.35-server</li>
<li>Tomcat 6.0.35（SSOエージェントマシン用）<br />
TOMCAT_HOME=C:\Program Files\apache-tomcat-6.0.35-agent</li>
<li>Windows XP SP3</li>
<li>OpenAM（openam_954.war）</li>
<li>J2EE Policy Agent（tomcat_v6_agent_3.zip）</li>
</ul>
<p>今回は、JavaEEサーバーにエージェントを組み込む、「エージェント型」で動かしてみる。<br />
また、OpenSSOを組み込むTomcat（SSOサーバー用）とSSOエージェントを組み込むTomcat（SSOエージェント用）は、必ず別にする必要がある（SSOエージェントをインストールする際に、SSOサーバー用Tomcatは起動していて、SSOエージェント用Tomcatは停止している必要があるため）</p>
<h3>手順</h3>
<ol>
<li>OpenAMをインストール</li>
<li>OpenAMにプロファイルを作成</li>
<li>SSOエージェントをインストール</li>
<li>SSO対象のWebアプリにフィルタを設定</li>
<li>OpenAMにポリシーを作成</li>
<li>確認</li>
</ol>
<h2>1. OpenAMをインストール</h2>
<p>SSOサーバーとして機能するOpenAMは、JavaのWebアプリとして配布されているので、配備はWARをデプロイするだけです。<br />
以下から、WAR（openam_954.war）をダウンロードする。<br />
<a href="http://www.forgerock.org/openam.html" target="_blank">http://www.forgerock.org/openam.html</a></p>
<p>WARを以下のように配置する（openam_954.war を openam.war にリネームした）</p>
<pre>
C:\Program Files\apache-tomcat-6.0.35_server\webapps\openam.war
</pre>
<p>Tomcatを起動したら、以下にアクセスする。<br />
<a href="http://sso.server.com:8080/openam" target="_blank" class="broken_link">http://sso.server.com:8080/openam</a></p>
<p>以下の画面が出れば正常にデプロイされている。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/01.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/01-600x464.png" alt="" title="01" width="600" height="464" class="alignnone size-large wp-image-504" /></a></p>
<p>「デフォルト設定の作成」を選択する。<br />
パスワードは、以下。</p>
<ul>
<li>amAdmin ： password1</li>
<li>UrlAccessAgent ： password2</li>
</ul>
<p>インストールが始まる。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/02.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/02-600x464.png" alt="" title="02" width="600" height="464" class="alignnone size-large wp-image-505" /></a></p>
<p>正常に完了したら、「ログインに進む」をクリックする。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/03.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/03-600x464.png" alt="" title="03" width="600" height="464" class="alignnone size-large wp-image-506" /></a></p>
<p>「amAdmin」ユーザのID、パスワードを入力すればログインできる（IDは大文字・小文字を区別しないようだ）</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/04.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/04-600x464.png" alt="" title="04" width="600" height="464" class="alignnone size-large wp-image-507" /></a></p>
<p>ログイン成功！</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/05.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/05-600x464.png" alt="" title="05" width="600" height="464" class="alignnone size-large wp-image-508" /></a></p>
<h2>2. OpenAMにプロファイルを作成</h2>
<p>引き続きそのままプロファイルを作成する。<br />
プロファイルは～～みたいなものだと思います。<br />
[アクセス制御]タブ → [/ (最上位のレルム)] → [エージェント]タブ → [J2EE]タブ に移動する。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/06.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/06-600x464.png" alt="" title="06" width="600" height="464" class="alignnone size-large wp-image-509" /></a></p>
<p>「エージェント」の「新規&#8230;」ボタンをクリックして、プロファイルを作成する。</p>
<ul>
<li>名前 ： <strong>tomcatagent</strong></li>
<li>パスワード ： <strong>password3</strong></li>
<li>設定 ： <strong>集中</strong></li>
<li>サーバーURL ： <strong>http://sso.server.com:8080/openam</strong></li>
<li>エージェントURL ： <strong>http://sso.agent.com:8080/agentapp</strong></li>
</ul>
<p>名前、パスワード、サーバーURL、エージェントURLは以降でも使うので、覚えておく。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/07.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/07-600x464.png" alt="" title="07" width="600" height="464" class="alignnone size-large wp-image-510" /></a></p>
<p>ついでに、クロスドメインの設定もしておく<br />
先ほど作成した、[tomcatagent] → [SSO]タブ → [クロスドメインSSO] に移動し、「有効」のチェックを付け、ページ上部の「保存」ボタンを押下する。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/08.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/08-600x464.png" alt="" title="08" width="600" height="464" class="alignnone size-large wp-image-511" /></a></p>
<h2>3. SSOエージェントをインストール</h2>
<p>（SSOエージェント用マシンで実施）<br />
まず以下から、ZIPをダウンロードし、解凍する。<br />
<a href="http://www.forgerock.org/openam.html" target="_blank">http://www.forgerock.org/openam.html</a><br />
場所は以下にした（この場所をエージェントが参照しているようなので、日本語パス等は避けたほうがいいかも）</p>
<pre>
C:\work\SSO\j2ee_agents
</pre>
<p>次に、プロファイルで設定したパスワードをパスワードファイルとして保存しておく必要がある。<br />
以下に、「pass」というファイル名でパスワードファイルを作成した（場所はどこでもいいと思う）</p>
<pre>
C:\Program Files\apache-tomcat-6.0.35-agent\agentpass\pass
</pre>
<p>そして、このファイルにパスワードを平文で記述する（ここでは「password3」）</p>
<p>これで、準備が整ったので以下を実行する（SSOサーバー用のTomcatを起動しておくこと）</p>
<pre>
C:\work\SSO\j2ee_agents\tomcat_v6_agent\bin\agentadmin.bat --install
</pre>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/09.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/09-600x437.png" alt="" title="09" width="600" height="437" class="alignnone size-large wp-image-512" /></a></p>
<ol>
<li>Enter the Tomcat Server Config Directory Path→ <strong>C:\Program Files\apache-tomcat-6.0.35-agent\conf</strong></li>
<li>OpenSSO server URL→ <strong>http://sso.server.com:8080/openam</strong></li>
<li>Enter the $CATALINA_HOME environment variable→ <strong>C:\Program Files\apache-tomcat-6.0.35-agent</strong></li>
<li>Install agent filter in global web.xml ?→ <strong>false</strong></li>
<li>Agent URL→ <strong>http://sso.agent.com:8080/agentapp</strong></li>
<li>Enter the Agent Profile name→ <strong>tomcatagent</strong></li>
<li>Enter the path to the password file→ <strong>C:\Program Files\apache-tomcat-6.0.35-agent\agentpass\pass</strong></li>
</ol>
<p>あと、忘れずに、以下のフォルダにある「agentapp.war」をエージェント用のTomcatに配備（C:\Program Files\apache-tomcat-6.0.35-agent\webapps）しておく。</p>
<pre>
C:\work\SSO\j2ee_agents\tomcat_v6_agent\etc
</pre>
<h2>4. SSO対象のWebアプリにフィルタを設定</h2>
<p>これで、SSOを行う準備が整ったので、SSO対象のWEBアプリへのリクエストがエージェントを経由するように、WEBアプリのweb.xmlにフィルタを作成する。</p>
<pre>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:web=&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
    xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
    id=&quot;WebApp_ID&quot; version=&quot;2.5&quot;&gt;
    &lt;display-name&gt;SampleWeb2&lt;/display-name&gt;

    &lt;filter&gt;
        &lt;filter-name&gt;Agent&lt;/filter-name&gt;
        &lt;filter-class&gt;com.sun.identity.agents.filter.AmAgentFilter&lt;/filter-class&gt;
    &lt;/filter&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;Agent&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
        &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
        &lt;dispatcher&gt;INCLUDE&lt;/dispatcher&gt;
        &lt;dispatcher&gt;FORWARD&lt;/dispatcher&gt;
        &lt;dispatcher&gt;ERROR&lt;/dispatcher&gt;
    &lt;/filter-mapping&gt;

    &lt;servlet&gt;
        &lt;servlet-name&gt;Sample1&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.sample.Sample1&lt;/servlet-class&gt;
    &lt;/servlet&gt;
    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;Sample1&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/Sample1&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;Sample2&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.sample.Sample2&lt;/servlet-class&gt;
    &lt;/servlet&gt;
    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;Sample2&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/Sample2&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;
&lt;/web-app&gt;
</pre>
<p>大事なところはフィルタ「Agent」です。これでこのアプリへの全てのリクエストがエージェントを経由することになる。</p>
<p>ちなみにサンプル用のWEBアプリは以下のような構成。</p>
<table border="1">
<tr>
<th>アプリケーション</th>
<th>アクセスパス</th>
<th>アクセスできるユーザー</th>
</tr>
<tr>
<td rowspan="2">SampleWeb1</td>
<td>/SampleWeb1/Sample1</td>
<td>sample0, sample1</td>
</tr>
<tr>
<td>/SampleWeb1/Sample2</td>
<td>sample0, sample1</td>
</tr>
<tr>
<td rowspan="2">SampleWeb2</td>
<td>/SampleWeb2/Sample1</td>
<td>sample0, sample2</td>
</tr>
<tr>
<td>/SampleWeb2/Sample2</td>
<td>sample0, sample2</td>
</tr>
</table>
<h2>5. OpenAMにポリシーを作成</h2>
<p>最後に、OpenAMにどのURLをどのユーザに許可するなどのポリシーを作成する。<br />
まずユーザーを作成しておく。<br />
[アクセス制御]タブ → [/ (最上位のレルム)] → [対象]タブ で「新規&#8230;」ボタンを押下し、ユーザーを作成する。<br />
今回は先ほど書いてるように「sample0, sample1, sample2」を作成した。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/10.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/10-600x464.png" alt="" title="10" width="600" height="464" class="alignnone size-large wp-image-513" /></a></p>
<p>次にポリシーを作成する。<br />
[アクセス制御]タブ → [/ (最上位のレルム)] → [ポリシー]タブ で「新規ポリシー&#8230;」ボタンを押下する。</p>
<p><strong>一般</strong><br />
名前 ： SampleWeb1</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/11.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/11-600x464.png" alt="" title="11" width="600" height="464" class="alignnone size-large wp-image-514" /></a></p>
<p><strong>ルール</strong><br />
サービスタイプ ： URL ポリシーエージェント (リソース名あり)<br />
名前 ： Sample1<br />
リソース名 ： http://sso.agent.com:8080/SampleWeb1/Sample1<br />
アクション ： GET,POST（共に許可）</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/12.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/12-600x464.png" alt="" title="12" width="600" height="464" class="alignnone size-large wp-image-515" /></a></p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/13.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/13-600x464.png" alt="" title="13" width="600" height="464" class="alignnone size-large wp-image-516" /></a></p>
<p>同様にして「/SampleWeb1/Sample2」を許可するルールも追加しておく。</p>
<p><strong>対象</strong><br />
タイプ ： OpenAM アイデンティティー対象<br />
名前 ： identity1<br />
sample0, sample1 を選択</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/14.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/14-600x464.png" alt="" title="14" width="600" height="464" class="alignnone size-large wp-image-517" /></a></p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/15.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/15-600x464.png" alt="" title="15" width="600" height="464" class="alignnone size-large wp-image-518" /></a></p>
<p>SampleWeb2用の新規ポリシーも上記と同様にして作成する。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/16.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/16-600x464.png" alt="" title="16" width="600" height="464" class="alignnone size-large wp-image-519" /></a></p>
<h2>6. 確認</h2>
<p>最後に正しく、SSOとアクセス制御が出来ているか確認する。<br />
エージェントが組み込まれたTomcatが起動していない場合は起動する。</p>
<p><a href="http://sso.agent.com:8080/SampleWeb1/Sample1" target="_blank" class="broken_link">http://sso.agent.com:8080/SampleWeb1/Sample1</a> にアクセス。未ログインなので、ログイン画面が表示される。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/17.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/17-600x464.png" alt="" title="17" width="600" height="464" class="alignnone size-large wp-image-520" /></a></p>
<p>「sample1」でログインすると、正常にアプリにアクセスできる。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/18.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/18-600x464.png" alt="" title="18" width="600" height="464" class="alignnone size-large wp-image-521" /></a></p>
<p><a href="http://sso.agent.com:8080/SampleWeb2/Sample1" target="_blank" class="broken_link">http://sso.agent.com:8080/SampleWeb2/Sample1</a> にアクセス。権限が無いので、403エラーになる。<br />
<a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/19.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/19-600x464.png" alt="" title="19" width="600" height="464" class="alignnone size-large wp-image-522" /></a></p>
<p>一旦、ログアウト（<a href="http://sso.server.com:8080/openam/UI/Logout" target="_blank" class="broken_link">http://sso.server.com:8080/openam/UI/Logout</a> にアクセス）して、<br />
再度、<a href="http://sso.agent.com:8080/SampleWeb1/Sample1" target="_blank" class="broken_link">http://sso.agent.com:8080/SampleWeb1/Sample1</a> にアクセス。今度は「sample0」でログインする。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/20.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/20-600x464.png" alt="" title="20" width="600" height="464" class="alignnone size-large wp-image-523" /></a></p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2012/03/21.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2012/03/21-600x464.png" alt="" title="21" width="600" height="464" class="alignnone size-large wp-image-524" /></a></p>
<p>「sample0」は別アプリの /SampleWeb1 と /SampleWeb2 にそれぞれアクセスできる。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2012/03/openam%e6%97%a7opensso%e3%81%a7%e3%82%b7%e3%83%b3%e3%82%b0%e3%83%ab%e3%82%b5%e3%82%a4%e3%83%b3%e3%82%aa%e3%83%b3%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>なぜ Java の配列は共変で、Generics は共変ではないのか</title>
		<link>http://sinsengumi.net/blog/2011/12/%e3%81%aa%e3%81%9c-java-%e3%81%ae%e9%85%8d%e5%88%97%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%80%81generics-%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%81%af%e3%81%aa%e3%81%84%e3%81%ae%e3%81%8b/</link>
		<comments>http://sinsengumi.net/blog/2011/12/%e3%81%aa%e3%81%9c-java-%e3%81%ae%e9%85%8d%e5%88%97%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%80%81generics-%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%81%af%e3%81%aa%e3%81%84%e3%81%ae%e3%81%8b/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 14:42:28 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Generics]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=472</guid>
		<description><![CDATA[まず、Java の配列がタイプセーフではない話。 public class ExampleArray { public static void main(String[] args) { String[] strArra [...]]]></description>
			<content:encoded><![CDATA[<p>まず、Java の配列がタイプセーフではない話。</p>
<pre>
public class ExampleArray {

    public static void main(String[] args) {
        String[] strArray = {&quot;test1&quot;, &quot;test2&quot;};
        Object[] objArray = strArray; // 配列は共変なので代入可能

        objArray[0] = new Integer(3); // java.lang.ArrayStoreException
    }
}
</pre>
<p>上記のように、Java の配列は共変という性質を持っているので、Object[] に String[] を代入することができます。つまり、<strong>String[] は Object[] のサブクラス</strong>である、ということです。<br />
しかし、Generics の場合は、この性質が当てはまりません（Generics は共変ではない）</p>
<pre>
public class ExampleGenerics {

    public static void main(String[] args) {
        List&lt;String&gt; strList = new ArrayList&lt;String&gt;();
        strList.add(&quot;test1&quot;);
        strList.add(&quot;test2&quot;);

        List&lt;Object&gt; objList = new ArrayList&lt;Object&gt;();

        objList = strList; // コンパイルエラー
    }
}
</pre>
<p>なぜ、配列は共変で、Generics は共変ではないのか？（一緒の方が分かりやすいのに）</p>
<p>その理由の前に、<br />
配列の例で見たように、型の混入現象は、強い型付け言語である Java としては避けたい現象です。<br />
配列の場合は、不正な型が混入した場所で例外（java.lang.ArrayStoreException）を投げてくれます。<br />
（これは、結構大事な所で、使用時(get)ではなく、設定時(set)にきちんと例外を投げてくれると、バグの混入場所が特定しやすいです）<br />
なぜこんなことができるかというと、配列は自分が何の型であるかを自身で知っている(バイトコードに型情報が存在する)ので、違う型を入れたときに、自分と違うということが判定できるのです。</p>
<p>一方、Generics の場合はコンパイル時に型消去という操作が行われます。<br />
型消去については、別エントリーでも書いてます（<a href="http://sinsengumi.net/blog/2011/12/generics%EF%BC%88java%EF%BC%89%E3%81%AE%E5%9E%8B%E6%B6%88%E5%8E%BB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/">Generics（Java）の型消去について</a>）</p>
<p><strong>Generics のコードは、コンパイル後にはその型情報を一切残していないので、java.lang.ArrayStoreException のような例外を投げることができません。<br />
そのため、共変ではなくして、型の混入を防いでいるのではないかと思います。</strong></p>
<p>Generics で共変っぽいことをしたい場合は、extends とかの境界条件をつければ可能です。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/12/%e3%81%aa%e3%81%9c-java-%e3%81%ae%e9%85%8d%e5%88%97%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%80%81generics-%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%81%af%e3%81%aa%e3%81%84%e3%81%ae%e3%81%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JPA Hibernate (H2 database) をやってみる</title>
		<link>http://sinsengumi.net/blog/2011/12/jpa-hibernate-h2-database-%e3%82%92%e3%82%84%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/</link>
		<comments>http://sinsengumi.net/blog/2011/12/jpa-hibernate-h2-database-%e3%82%92%e3%82%84%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 02:37:19 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[H2 database]]></category>
		<category><![CDATA[JPA]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=446</guid>
		<description><![CDATA[最近、Play framework が面白いなぁと思ってちょろちょろ遊んでたりするんですが、Play はモデル層に JPA を採用していて、実は JPA って一度も触った事が無かったのでこれを機にどういうものなのか試して [...]]]></description>
			<content:encoded><![CDATA[<p>最近、<a href="http://playdocja.appspot.com/" target="_blank">Play framework</a> が面白いなぁと思ってちょろちょろ遊んでたりするんですが、Play はモデル層に JPA を採用していて、実は JPA って一度も触った事が無かったのでこれを機にどういうものなのか試して見ました。</p>
<h2>プロジェクトの準備</h2>
<p>JPA は昔は Java EE(EJB) でしか使えなかったらしいですが、スタンドアロンでも使えるようになったらしいので、スタンドアロンで試してみます。</p>
<p>JPA の実装は Hibernate を使用します。<br />
この Hibernate がやたら依存モジュールが多いので、簡単のため maven プロジェクトにします。</p>
<pre>
mvn archetype:create -DgroupId=com.example -DartifactId=JPASample
</pre>
<p>pom.xml に以下を書いておく。<br />
pom.xml に追加する jar は<a href="http://docs.jboss.org/hibernate/core/3.6/reference/ja-JP/html_single/#tutorial-firstapp-setup" target="_blank">ここらへん</a>を参考にしました。注意点としては、JPA を使用するには、<strong>hibernate-entitymanager</strong> というモジュールが必要なのでそれを必ず追加しておくこと。<br />
あとは、永続化先に使用する DB の JDBC も忘れずに追加しておくこと（今回は H2 database を使用）</p>
<pre>
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;com.example&lt;/groupId&gt;
    &lt;artifactId&gt;JPASample2&lt;/artifactId&gt;
    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;

    &lt;name&gt;JPASample2&lt;/name&gt;
    &lt;url&gt;http://maven.apache.org&lt;/url&gt;

    &lt;properties&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;junit&lt;/groupId&gt;
            &lt;artifactId&gt;junit&lt;/artifactId&gt;
            &lt;version&gt;3.8.1&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;

        &lt;dependency&gt;
            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
            &lt;artifactId&gt;hibernate-core&lt;/artifactId&gt;
            &lt;version&gt;3.6.8.Final&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
            &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;
            &lt;version&gt;3.6.8.Final&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;slf4j-simple&lt;/artifactId&gt;
            &lt;version&gt;1.6.4&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.h2database&lt;/groupId&gt;
            &lt;artifactId&gt;h2&lt;/artifactId&gt;
            &lt;version&gt;1.3.162&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/project&gt;
</pre>
<p>できたプロジェクトを Eclipse にインポートさせるため、以下のコマンドを叩いて Eclipse プロジェクトにしておく。</p>
<pre>
cd JPASample
mvn eclipse:eclipse
</pre>
<p>できたら、Eclipse からインポートする。</p>
<h2>データベース の準備</h2>
<p>永続先として今回は H2 database を使用。Jar ファイル1つで完結するのでとても簡単。<br />
<a href="http://www.h2database.com/html/main.html" target="_blank">ここ</a>から Jar を DL して Jar 実行。</p>
<pre>
java -jar h2-1.3.162.jar
</pre>
<p>Web コンソールが立ち上がると思うので、ログイン（ID、パスワードはそのままでOK）して、テーブルを作成しておく。</p>
<pre>
CREATE TABLE EMPLOYEE(ID INT PRIMARY KEY, NAME VARCHAR(255));
</pre>
<h2>JPA の準備</h2>
<p>まずテーブルにマッピングさせるエンティティクラスを作成する。</p>
<pre>
@Entity
public class Employee {

    @Id
    public int id;
    public String name;

    public Employee() {
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
</pre>
<p>次に、JPA が DB の設定などを行う persistence.xml を作成する。<br />
配置場所はクラスパスが通っている場所に配置する（今回は <code>src/main/resources/META-INF/persistence.xml</code> に配置した）<br />
Eclipse でちゃんとクラスパス設定を行うこと。</p>
<pre>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;persistence version=&quot;1.0&quot;
    xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd&quot;&gt;

    &lt;persistence-unit name=&quot;sample&quot; transaction-type=&quot;RESOURCE_LOCAL&quot;&gt;
        &lt;class&gt;com.example.Employee&lt;/class&gt;
        &lt;properties&gt;
            &lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.hibernate.dialect.H2Dialect&quot; /&gt;
            &lt;property name=&quot;hibernate.connection.driver_class&quot; value=&quot;org.h2.Driver&quot; /&gt;
            &lt;property name=&quot;hibernate.connection.username&quot; value=&quot;sa&quot; /&gt;
            &lt;property name=&quot;hibernate.connection.password&quot; value=&quot;&quot; /&gt;
            &lt;property name=&quot;hibernate.connection.url&quot; value=&quot;jdbc:h2:tcp://localhost:9092/demo&quot; /&gt;
            &lt;property name=&quot;hibernate.max_fetch_depth&quot; value=&quot;3&quot; /&gt;
        &lt;/properties&gt;
    &lt;/persistence-unit&gt;
&lt;/persistence&gt;
</pre>
<h2>実行</h2>
<p>あとは、JPA を使って実行するのみ。</p>
<pre>
public class App {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;sample&quot;);
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            em.persist(new Employee(1, &quot;近藤 勇&quot;));
            em.persist(new Employee(2, &quot;土方 歳三&quot;));

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
            emf.close();
        }
    }
}
</pre>
<p>H2 database にデータがきちんと登録されていれば成功。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/12/jpa-hibernate-h2-database-%e3%82%92%e3%82%84%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generics（Java）の型消去について</title>
		<link>http://sinsengumi.net/blog/2011/12/generics%ef%bc%88java%ef%bc%89%e3%81%ae%e5%9e%8b%e6%b6%88%e5%8e%bb%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/</link>
		<comments>http://sinsengumi.net/blog/2011/12/generics%ef%bc%88java%ef%bc%89%e3%81%ae%e5%9e%8b%e6%b6%88%e5%8e%bb%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/#comments</comments>
		<pubDate>Sun, 04 Dec 2011 03:39:51 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Generics]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=437</guid>
		<description><![CDATA[Java の Generics の実装方式の型消去についてちょっと調べました。 そもそも ジェネリックプログラミングというのは、Java だけにあるものではなく色んな言語に同様の機能があるようです。 ジェネリックプログラ [...]]]></description>
			<content:encoded><![CDATA[<p>Java の Generics の実装方式の型消去についてちょっと調べました。</p>
<p>そもそも ジェネリックプログラミングというのは、Java だけにあるものではなく色んな言語に同様の機能があるようです。<br />
<a href="http://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0" title="ジェネリックプログラミング wikipedia" target="_blank">ジェネリックプログラミング wikipedia</a></p>
<p>Java の場合、言語仕様的に、どうやって Generics を実装しているかというと「型消去（type erasure）」によって行われている。<br />
型消去とは、「コンパイル後のバイトコードに<strong>型情報</strong>を残さない」ということ。</p>
<p>具体的なサンプルコードで見てみる。</p>
<pre>
public void method15() {
    List&lt;String&gt; list = new ArrayList&lt;String&gt;();
    list.add(&quot;string&quot;);
    String str = list.get(0);
}

public void method14() {
     List list = new ArrayList();
     list.add(&quot;string&quot;);
     String str = (String) list.get(0);
}
</pre>
<p>これを、jad したものが以下。</p>
<pre>
  public void method15();
     0  new java.util.ArrayList [15]
     3  dup
     4  invokespecial java.util.ArrayList() [17]
     7  astore_1 [list]
     8  aload_1 [list]
     9  ldc &lt;String &quot;string&quot;&gt; [18]
    11  invokeinterface java.util.List.add(java.lang.Object) : boolean [20] [nargs: 2]
    16  pop
    17  aload_1 [list]
    18  iconst_0
    19  invokeinterface java.util.List.get(int) : java.lang.Object [26] [nargs: 2]
    24  checkcast java.lang.String [30]
    27  astore_2 [str]
    28  return

  public void method14();
     0  new java.util.ArrayList [15]
     3  dup
     4  invokespecial java.util.ArrayList() [17]
     7  astore_1 [list]
     8  aload_1 [list]
     9  ldc &lt;String &quot;string&quot;&gt; [18]
    11  invokeinterface java.util.List.add(java.lang.Object) : boolean [20] [nargs: 2]
    16  pop
    17  aload_1 [list]
    18  iconst_0
    19  invokeinterface java.util.List.get(int) : java.lang.Object [26] [nargs: 2]
    24  checkcast java.lang.String [30]
    27  astore_2 [str]
    28  return
</pre>
<p>確かに、コンパイルされると型情報が消去されて、Java 1.4 時代のものと同じになっている。</p>
<h2>なぜ、Java では型消去という実装方式を採用したか？</h2>
<p>C++ の場合、同様の機能にテンプレートというものがあるらしく、そちらはコンパイル後も型情報をインライン展開して残すらしいです。<br />
で、Java の場合、なぜ型消去という実装方式を採用したかというと、「<strong>後方互換性</strong>」のためらしい。</p>
<p>先の例で見たように、コンパイル後のコードが全く同じになるので、1.4 以前で書かれたコードと 1.5 以上で書かれてコードがコードが混在していても実行できる、ということ。</p>
<p>なるほど、よく出来てる。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/12/generics%ef%bc%88java%ef%bc%89%e3%81%ae%e5%9e%8b%e6%b6%88%e5%8e%bb%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Servlet 3.0 のアノテーションでは Filter の順番を指定できない？</title>
		<link>http://sinsengumi.net/blog/2011/12/servlet-3-0-%e3%81%ae%e3%82%a2%e3%83%8e%e3%83%86%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%a7%e3%81%af-filter-%e3%81%ae%e9%a0%86%e7%95%aa%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%a7%e3%81%8d%e3%81%aa%e3%81%84/</link>
		<comments>http://sinsengumi.net/blog/2011/12/servlet-3-0-%e3%81%ae%e3%82%a2%e3%83%8e%e3%83%86%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%a7%e3%81%af-filter-%e3%81%ae%e9%a0%86%e7%95%aa%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%a7%e3%81%8d%e3%81%aa%e3%81%84/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 12:20:19 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Servlet]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=429</guid>
		<description><![CDATA[Servlet 3.0 になってから HttpServlet クラスの @WebServlet 同様に、Filter クラスも @WebFilter というアノテーションが指定できるようになっていて、やたら便利です。 @ [...]]]></description>
			<content:encoded><![CDATA[<p>Servlet 3.0 になってから HttpServlet クラスの @WebServlet 同様に、Filter クラスも @WebFilter というアノテーションが指定できるようになっていて、やたら便利です。</p>
<pre>
@WebFilter(dispatcherTypes = { DispatcherType.REQUEST }, urlPatterns = { &quot;/*&quot; },
        initParams = { @WebInitParam(name = &quot;encoding&quot;, value = &quot;UTF-8&quot;) })
public class EncodingFilter implements Filter {

    private String encoding = null;

    @Override
    public void init(FilterConfig fConfig) throws ServletException {
        encoding = fConfig.getInitParameter(&quot;encoding&quot;);
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request, response);
    }
}
</pre>
<p>が、どうもアノテーションだけでは、Filter クラスの順番を定義することはできないようです。<br />
なので、結局、web.xml に Filter を上から順番に書いていくしかないようです、残念。<br />
（指定する方法があったら教えて欲しいです）</p>
<p>ちなみに @WebFilter に指定するアノテーション定義はこちら<br />
<a href="http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebFilter.html">http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebFilter.html</a></p>
<p>やはり、順番を指定する指定は無いっぽい。</p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/12/servlet-3-0-%e3%81%ae%e3%82%a2%e3%83%8e%e3%83%86%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%a7%e3%81%af-filter-%e3%81%ae%e9%a0%86%e7%95%aa%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%a7%e3%81%8d%e3%81%aa%e3%81%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LDRich という livedoor Reader のクライアントアプリを作りました</title>
		<link>http://sinsengumi.net/blog/2011/11/ldrich/</link>
		<comments>http://sinsengumi.net/blog/2011/11/ldrich/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 14:37:47 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ldr4j]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=417</guid>
		<description><![CDATA[Android で何か作りたくて、勢いで Galaxy S を買ってしまったので、アプリを作りました。 LDRich という Android アプリで、livedoor Reader のクライアントです。 ネーミングに特 [...]]]></description>
			<content:encoded><![CDATA[<p>Android で何か作りたくて、勢いで Galaxy S を買ってしまったので、アプリを作りました。</p>
<p>LDRich という Android アプリで、livedoor Reader のクライアントです。<br />
ネーミングに特に意味はなくて、思いついたものは全て使われていて、ゴロで決めました。</p>
<p><a href="http://sinsengumi.net/blog/wp-content/uploads/2011/11/capture_01.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2011/11/capture_01-180x300.png" alt="" title="capture_01" width="180" height="300" class="alignnone size-medium wp-image-419" /></a><br />
<a href="http://sinsengumi.net/blog/wp-content/uploads/2011/11/capture_02.png"><img src="http://sinsengumi.net/blog/wp-content/uploads/2011/11/capture_02-180x300.png" alt="" title="capture_02" width="180" height="300" class="alignnone size-medium wp-image-421" /></a></p>
<p>Android 使っている人で、livedoor Reader ユーザーは使っていただけたら嬉しいです。</p>
<p><a href="https://market.android.com/details?id=net.sinsengumi.ldrich">Android Market</a><br />
<a href="http://sinsengumi.net/ldrich/">使い方の解説ページ</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/11/ldrich/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>msysGitのGit bashで日本語を使えるようになるまで</title>
		<link>http://sinsengumi.net/blog/2011/08/msysgit%e3%81%aegit-bash%e3%81%a7%e6%97%a5%e6%9c%ac%e8%aa%9e%e3%82%92%e4%bd%bf%e3%81%88%e3%82%8b%e3%82%88%e3%81%86%e3%81%ab%e3%81%aa%e3%82%8b%e3%81%be%e3%81%a7/</link>
		<comments>http://sinsengumi.net/blog/2011/08/msysgit%e3%81%aegit-bash%e3%81%a7%e6%97%a5%e6%9c%ac%e8%aa%9e%e3%82%92%e4%bd%bf%e3%81%88%e3%82%8b%e3%82%88%e3%81%86%e3%81%ab%e3%81%aa%e3%82%8b%e3%81%be%e3%81%a7/#comments</comments>
		<pubDate>Mon, 08 Aug 2011 02:34:20 +0000</pubDate>
		<dc:creator>sinsengumi</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Github]]></category>

		<guid isPermaLink="false">http://sinsengumi.net/blog/?p=404</guid>
		<description><![CDATA[最近、ようやくGitを使い始めました。サクサク感があっていいですね。あとGithubの存在が大きい。 で、表題なんですが、 僕はWindows派でmsysGit使ってるわけですが、デフォルト状態（Git Bash）ではコ [...]]]></description>
			<content:encoded><![CDATA[<p>最近、ようやくGitを使い始めました。サクサク感があっていいですね。あとGithubの存在が大きい。</p>
<p>で、表題なんですが、<br />
僕はWindows派でmsysGit使ってるわけですが、デフォルト状態（Git Bash）ではコミットログの日本語が化けて出たりと何かと不便です。<br />
そこで、いろいろ設定して日本語が表示できるようになろうという感じです。</p>
<h2>lessとnkfをインストール</h2>
<p>以下を参考に、lessとnkfを導入します。<br />
<a href="http://sourceforge.jp/magazine/09/02/12/0530242/3">http://sourceforge.jp/magazine/09/02/12/0530242/3</a></p>
<p>inputrc</p>
<pre>
set meta-flag on
set input-meta on
set output-meta on
set convert-meta off
set kanji-code utf-8
</pre>
<p>profile</p>
<pre>
export GIT_PAGER="nkf -s | less"
</pre>
<p>GIT_EDITORの設定は~/.gitconfigで行っているのでここでは設定しません。</p>
<h2>~/.gitconfigの設定</h2>
<p>以下のように修正。</p>
<pre>
[user]
	name = sinsengumi
	email = tomoya.sinsengumi@gmail.com
[color]
	ui = auto
[core]
	editor = 'C:/Program Files (x86)/sakura2-0-2-0/sakura.exe' -CODE=4
	autocrlf = false
[alias]
	ci = commit
	co = checkout
	st = status
	di = diff
	sh = show
	br = branch
[i18n]
	commitencoding = UTF-8
</pre>
<p>editorの部分ではサクラエディタを起動してますが、「-CODE=4」はファイルを開く時にUTF-8で開くという起動オプションです。</p>
<p>ちなみにこの設定はGithubに上げてみました^^;<br />
<a href="https://github.com/sinsengumi/Configs">https://github.com/sinsengumi/Configs</a></p>
<h3>参考</h3>
<ul>
<li><a href="http://sourceforge.jp/magazine/09/02/12/0530242/3">http://sourceforge.jp/magazine/09/02/12/0530242/3</a></li>
<li><a href="http://d.hatena.ne.jp/kaorun55/20110222/1298306709" class="broken_link">http://d.hatena.ne.jp/kaorun55/20110222/1298306709</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://sinsengumi.net/blog/2011/08/msysgit%e3%81%aegit-bash%e3%81%a7%e6%97%a5%e6%9c%ac%e8%aa%9e%e3%82%92%e4%bd%bf%e3%81%88%e3%82%8b%e3%82%88%e3%81%86%e3%81%ab%e3%81%aa%e3%82%8b%e3%81%be%e3%81%a7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

