ラベル jetty の投稿を表示しています。 すべての投稿を表示
ラベル jetty の投稿を表示しています。 すべての投稿を表示

2014年5月13日火曜日

Jetty 9.1.* の設定について

jetty 9.1.*系以降jettyの一部がモジュール化され
設定項目体系が変わっています

設定方法についてをすこしまとめておきます。


1.httpsを有効化

ダウンロードしたアーカイブのdemo-base以下にあるstart.d/ssl.ini、https.iniが参考になります
demo-baseのstart.d/ssl.ini、https.iniを start.dにコピペして
環境に合わせて修正する


2. jetty-envを有効化

そのままでOKただし、pom.xmlにjetty関連のdependancyがある場合
loaderエラーになる可能性があるのでjetty pluginでのみ必要な物は
jetty plugin 以下のdependancyに移す


3. jspを有効化

start.iniの--module=jspのコメントを外す


4. servletを有効化

defaultでservletsモジュールは読み込まれないので
jetty-servlets を使う場合は、
start.iniに--module=servletsを追加

 
5. リクエストログの有効化

start.iniに--module=requestlogを追加


等々

9.1.4はログ出力のリンク回りがバグっているのかjetty.shが動かない場合があるので注意
多分9.1.5で修正ずか?


2014年3月25日火曜日

Session Counter Listener

セッション数をカウントするServlet コンテナ用のListenerを自作したので共有
サービスのセッション数 を監視してーという人はどうぞ
thread safeなはず。 Java1.5以上必要です


SessionCounterListener.java:

public class SessionCounterListener implements HttpSessionListener {
    private static AtomicInteger totalActiveSessions = new AtomicInteger();

    public static int getTotalActiveSession() {
        return totalActiveSessions.get();
    }

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        totalActiveSessions.incrementAndGet();
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {
        totalActiveSessions.decrementAndGet();
    }
}


web.xmlにはListenerとして登録

web.xml :

 <listener>
        <listener-class>my.package.SessionCounterListener</listener-class>
</listener>


   

2014年2月22日土曜日

Jersey2.6(JAX-RS2.2) with Jetty9 セットアップ


JAX-RS2.*を使いたいと思って、Jersey2.6をJetty9に組み込もうとしたのですが、
四苦八苦したのでメモ

いろいろdependancyに入れすぎてたのが問題だったようです。
jsr311-apiをdependancyから取り除くとうまくいきました。

JAX-RS2.*では、Pojomappingを指定するのではなく
JAX-RS JSON Providerに対応するライブラリを追加することでJSONに対応します。
下の例では、jackson-jaxrs-json-providerを追加しています。

JavaEE3以上は、jersey-container-servlet-coreを使うよう言われますが
自分は以前のweb.xmlでの指定方法が好みなので
jersey-container-servletを使っています。


pom.xml :

 <略>

<properties>
    <java.version>1.7</java.version>
    <jettyVersion>9.1.2.v20140210</jettyVersion>
    <jerseyVersion>2.6</jerseyVersion>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
   
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jettyVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jettyVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jerseyVersion}</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>${jerseyVersion}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>${jettyVersion}</version>
                <configuration>
                    <webAppSourceDirectory>${basedir}/webapp</webAppSourceDirectory>
                    <webXmlFile>${basedir}/webapp/WEB-INF/web.xml</webXmlFile>
                    <jettyEnvXml>${basedir}/webapp/WEB-INF/jetty-env.xml</jettyEnvXml>
                    <contextPath>/</contextPath>
                </configuration>
            </plugin>
        </plugins>
    </build>




WEB-INF/web.xml:


<?xml version="1.0" encoding="UTF-8"?>
<web-app>

    <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>パッケージ</param-value>
        </init-param>
        <load-on-startup>10</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>




WEB-INF/jetty-env.xml:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">

  <Call name="setAttribute">
      <Arg>org.eclipse.jetty.webapp.configuration</Arg>
      <Arg>
          <Array type="java.lang.String">
              <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
              <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
              <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
          </Array>
      </Arg>
    </Call>
 

  <Set name="war"><SystemProperty name="jetty.home" default="."/>/</Set>
 
</Configure>

2013年9月21日土曜日

J2EE (jetty) アプリケーション初期化処理

J2EE のリスナーの話です

基本のリスナーの使い方は覚えないといけないなー
と思いながら全然すすまない

まずは初期化処理から
初期化時にはDBからマスタの読み込みとかします


package com.gauuud.StartUp;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;


public class InitDB implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //初期化処理       
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        //終了時処理

    }

}


web.xml :

<listener>     
        <listener-class>com.gauuud.StartUp.InitDB</listener-class>
</listener>


余談になりますが
マスタは起動時にメモリ上に全部読み込むようにするべきですよね
最近のサーバはメモリ多いし(マスタとか10Mもいかないだろうし
クラスタ構成が多いので更新時に再起動でサービスが止まることもないし

2013年9月16日月曜日

JNDIのカスタムPropertyクラス2

jetty 8.1以降では

JNDI に Array を指定することが可能になっています
次のように指定可能です


web.xml



    <resource-ref>
        <description>Maintenance Property</description>
        <res-ref-name>maintenance</res-ref-name>
        <res-type>java.lang.reflect.Array</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>



jetty-env.xml



    <New id="maintenance" class="org.eclipse.jetty.plus.jndi.Resource">
        <Arg></Arg>
        <Arg>maintenance</Arg>
        <Arg>
              <Array type="com.gauuud.Property.MaintenanceProp">
                <item><New class="com.gauuud.Property.MaintenanceProp">
                    <Set name="start">2012/9/11 1:25</Set>
                    <Set name="end">2012/9/11 1:30</Set>
                    <Set name="type">10</Set>
                    <Set name="desc">test</Set>
                </New></item>
                <item><New class="com.gauuud.Property.MaintenanceProp">
                    <Set name="start">2012/9/12 1:25</Set>
                    <Set name="end">2012/9/13 1:30</Set>
                    <Set name="type">10</Set>
                    <Set name="desc">test2</Set>
                </New></item>
            </Array>
        </Arg>
    </New>




MaintenanceProp.java :



package com.gauuud.Property;

import java.util.Date;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;




public class MaintenanceProp {

    private int type;

    public int getType() {
        return this.type;
    }

    public void setType(int type) {
        this.type = type;
    }

    private Date start;

    public Date getStart() {
        return this.start;
    }

    public void setStart(Date start) {
        this.start = start;
    }

    private Date end;

    public Date getEnd() {
        return this.end;
    }

    public void setEnd(Date end) {
        this.end = end;
    }

    private String desc;

    public String getDesc() {
        return this.desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public MaintenanceProp() {}

}



MaintenancePropArray.java:



package com.gauuud.Property;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;



public class MaintenancePropArray {
    private static final MaintenanceProp[] array;
   
    public static MaintenanceProp[] get(){
        return array;
    }
   
    static {
        MaintenanceProp[] props = null;
        try {
            InitialContext ic = new InitialContext();
            Context envCtx = (Context) ic.lookup("java:comp/env");
            props = (MaintenanceProp[]) envCtx.lookup("maintenance");
        } catch (NamingException e) {
            e.printStackTrace();
        }
        array = props;
    }
}


Ubuntu 12.* Jetty のマニュアルインストール

Jettyの手動インストール方法です
レポジトリのjettyは古いし動かないし手動でインストールするしかありません

基本は参考文献の多いTomcatのまねをすればいいみたいです

※権限周りは知識がないので要確認です



1.Jettyをダウンロード
http://download.eclipse.org/jetty/stable-9/dist/



2.解凍

tar -xvf jetty-distribution-8.1.11.v20130520.tar.gz






3.移動、リンクはる
sudo mv jetty-distribution-8.1.11.v20130520 /usr/local/

cd /usr/local/

sudo ln -s  jetty-distribution-8.1.11.v20130520 jetty



4.スクリプトに権限付与

sudo useradd jetty -U -s /bin/false

#こっちかな?useradd jetty jetty -d /usr/local/jetty/ -s /bin/false -p’*’ -r

sudo chown -R jetty webapps temp logs work conf

sudo chmod a+x /usr/local/jetty/bin/jetty.sh

nano /usr/local/jetty/bin/jetty.sh

#1行目を修正

!/bin/bash




5.init.d登録


sudo cp bin/jetty.sh /etc/init.d/jetty

sudo chmod 755 /etc/init.d/jetty

sudo nano /etc/default/jetty

下記の内容を書き込む

JAVA_HOME=/usr/lib/jvm/jdk1.7.0 # Path to Java
NO_START=0 # Start on boot

PATH=${JAVA_HOME}/bin:${PATH}
JAVA_OPTION=-Duser.timezone="Asia/Tokyo" #TimeZoneの指定が必要なら
JETTY_HOME=/usr/local/jetty
JETTY_USER=jetty # Run as this user

開始してみる
sudo service jetty start



6.自動起動に登録

sudo update-rc.d jetty defaults


参考
http://jensontaylor.blogspot.jp/2010/09/manually-installing-tomcat-7-on-ubuntu.html


その他の設定
#ポート80を開く場合
iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -I PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443 

2013年1月5日土曜日

HttpServletRequestのthread内共有

ASP.NETを利用していると
static HttpContext HttpContext.Current からリクエスト情報を取得して
IPADDRESS等の情報をどこででも取得することができます

似たような意識でJavaで実装していると
どうしてもHttpServletRequestの取得でつまずいてしまいます。

そこで、スレッド毎に値を保持するThreadLocalを利用して
HttpServletRequest をスレッド内で参照できるようにします


private final static ThreadLocal<HttpServletRequest> servletRequests = new ThreadLocal<HttpServletRequest>();

public static void setServletRequest(HttpServletRequest request) {
    servletRequests.set(request);
}

public static HttpServletRequest getServletRequest() {
    return servletRequests.get();
}


もちろん非同期な実装では参照できなくなる(かな?)
リクエスト初期化時にセットする必要があります。
リクエスト終了後はガベージコレクション対象になります。

2013年1月4日金曜日

Logbackメモ


Logback を利用してログ出力しているのですが、
これまでサンプルのままだったのを少し見直しました。


次のような要件を満たすように変更、
1.レベルがエラーの場合にメールで送信する
2.ファイル出力、日毎、100M毎 にローリング


main/resource/logback.xml :

<?xml version="1.0"?>
 <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<configuration debug="true" scan="true" scanPeriod="30 seconds">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>

    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <smtpHost>smtp.gmail.com</smtpHost>
        <smtpPort>587</smtpPort>
        <STARTTLS>true</STARTTLS>
        <username>[YOUR_NAME]@gmail.com</username>
        <password>[YOUR_PASSWORD]</password>
        <to>[TO]</to> <!-- additional destinations are possible -->
        <from>[FROM]</from>
        <subject>TESTING: %logger{20} - %m</subject>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <charset>UTF-8</charset>
            <Pattern>[%-5level][%d{yyyy-MM-dd HH:mm:ss.SSS}] %class - %msg%n</Pattern>
        </layout>
    </appender>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>logFile.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- keep 30 days' worth of history -->
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 100MB -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <charset>UTF-8</charset>
            <Pattern>[%-5level][%d{yyyy-MM-dd HH:mm:ss.SSS}] %class - %msg%n</Pattern>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="FILE" />
        <appender-ref ref="STDOUT" />
        <appender-ref ref="EMAIL" />
    </root>
</configuration>



SMTPAppenderを利用してメールを送信します。
サンプルではGMAILで送信する設定にしています。
メールで送信する場合はLevelFilterを利用してERRORの場合のみ送信するようにしています。
File出力に関しては、ここのサンプルのままです。


File出力がネックになりそうな場合は、下のAsyncAppenderをFileAppenderの
前に挟んでAsync処理にする。
SMTPはAsyncで送信されているようなので気にしない 。

  <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE" />
  </appender>



アクセスログを出力したい場合は、ここを参照する

2013年1月3日木曜日

jetty maven gzipフィルター適用

maven上のjetty plugin でgzip を適用する方法。
このあたりの内容です。

http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin#Using_GZip_Compression_and_Other_Jetty_Extensions


pom.xmlのプラグイン設定にdependancyを追加

<plugin>
       
<groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>                                        <version>8.1.8.v20121106</version>
         <configuration>
           [...]
       
</configuration>
         <dependencies> 
         <dependency>
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-servlets</artifactId>
             <version>8.1.8.v20121106</version>
           </dependency>
         </dependencies>


web.xmlにgzipフィルターを定義

  <filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
    <init-param>
      <param-name>mimeTypes</param-name>
      <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>



pom.xmlにdependancyを追加していないと
ClassNotFoundExceptionで怒られます

2012年12月7日金曜日

JNDIのカスタムPropertyクラス

JNDIに設定を集約できないかと思い、カスタムPropertyクラス作ってみました。

 Jettyを利用している場合、
 xmlのNew要素に指定したclass属性のクラスをnewして、
その子要素のSetに指定した値をname属性と同じ名前のメンバに代入します。

何言ってるかわからんないですね。。つまり、
<New class="org.chikishe.Property.MemcachedProp">
                <Set name="servers">127.0.0.1:8091</Set>
                <Set name="weights" type="java.lang.String" >1</Set>
…

というxmlは、

MemcachedProp prop = new MemcachedProp();
prop.setServers("127.0.0.1:8091");
prop.setWeights("1"):
 …

というふうに解釈されます。

Memcached-Java-Client用のPropertyクラスを作るとするとこうなります。


MemcahedProp.java:

package org.chikishe.Property;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class MemcachedProp {
    private String[] servers;

    private Integer[] weights;

    private int initConn;

    private int minConn;

    private int maxConn;

    private int maxIdle;

    private int maintSleep;

    private boolean nagle;

    private int socketTO;

    private int socketConnectTO;

    public String[] getServers() {
        return servers;
    }

    public void setServers(String servers) {
        this.servers = servers.split(",");
    }

    public Integer[] getWeights() {
        return weights;
    }

    public void setWeights(String weights) {
        String[] strings = weights.split(",");
        Integer[] ints = new Integer[strings.length];
        for (int i = 0; i < strings.length; i++)
            ints[i] = Integer.parseInt(strings[i]);

        this.weights = ints;
    }

    public int getInitConn() {
        return initConn;
    }

    public void setInitConn(int initConn) {
        this.initConn = initConn;
    }

    public int getMinConn() {
        return minConn;
    }

    public void setMinConn(int minConn) {
        this.minConn = minConn;
    }

    public int getMaxConn() {
        return maxConn;
    }

    public void setMaxConn(int maxConn) {
        this.maxConn = maxConn;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMaintSleep() {
        return maintSleep;
    }

    public void setMaintSleep(int maintSleep) {
        this.maintSleep = maintSleep;
    }

    public boolean isNagle() {
        return nagle;
    }

    public void setNagle(boolean nagle) {
        this.nagle = nagle;
    }

    public int getSocketTO() {
        return socketTO;
    }

    public void setSocketTO(int socketTO) {
        this.socketTO = socketTO;
    }

    public int getSocketConnectTO() {
        return socketConnectTO;
    }

    public void setSocketConnectTO(int socketConnectTO) {
        this.socketConnectTO = socketConnectTO;
    }

    public MemcachedProp() {
    }

    public static MemcachedProp getInstance() throws NamingException {

        InitialContext ic = new InitialContext();
        Context envCtx = (Context) ic.lookup("java:comp/env");
        MemcachedProp prop = (MemcachedProp) envCtx.lookup("memcached");
        return prop;
    }

}


jetty-env.xml:

<New id="memcached" class="org.eclipse.jetty.plus.jndi.Resource">
        <Arg></Arg>
        <Arg>memcached</Arg>
        <Arg>
            <New class="org.chikishe.Property.MemcachedProp">
                <Set name="servers">127.0.0.1:8091</Set>
                <Set name="weights" type="java.lang.String" >1</Set>
                <Set name="initConn">5</Set>
                <Set name="minConn">5</Set>
                <Set name="maxConn">250</Set>
                <Set name="maxIdle">21600000</Set>
                <Set name="maintSleep">30</Set>
                <Set name="nagle">false</Set>
                <Set name="socketTO">3000</Set>
                <Set name="socketConnectTO">0</Set>
            </New>
        </Arg>
    </New>


web-inf/web.xml :

 <resource-ref>
     <description>Memcached Property</description>
     <res-ref-name>memcached</res-ref-name>
     <res-type>org.chikishe.Property.MemcachedProp</res-type>
     <res-auth>Container</res-auth>
  </resource-ref>



呼び出しはこんなふうになります。

MemcachedProp prop = MemcachedProp.getInstance();

SockIOPool pool = SockIOPool.getInstance();

// set the servers and the weights
pool.setServers(prop.getServers());
pool.setWeights(prop.getWeights());



とりあえず、JNDIに設定をまとめるには使えそうです。
本来はstatic finalにしたいところ。
あと、 Memcached-Java-ClientのJNDI対応まだないんでしょうか?



2012年1月15日日曜日

jetty + jersey + Amazon Product Advertising APIのサンプル

●xsdからjarファイルの作成

 AmazonのAmazon Product Advertising APIを利用する際には、
jaxbでxmlをパースするためにクラスの定義が必要です。
ここでは、アマゾンの提供しているxsdからクラス定義を含むjarファイルを作成します。

まず、アマゾンからAWSECommerceService.xsd をダウンロードし、
src/main/resourcesに設置。

pom.xmlを下記のように追加。
maven-compiler-pluginは、1.5以上に設定する。

<groupId>test</groupId>
<artifactId>aws-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>AWSECommerceService</name>

<dependencies>
<dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.2.6</version>
  </dependency> 
  </dependencies>
  <build>
      <plugins>
           <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>6</source>
                <target>6</target>
            </configuration>
      </plugin>
     <plugin>
          <groupId>org.jvnet.jaxb2.maven2</groupId>
          <artifactId>maven-jaxb22-plugin</artifactId>
          <version>0.8.0</version>
      </plugin> 
     </plugins>
  </build>

maven packageを実行すると、target以下にjarファイルが作成されます。
(著者は、target/generated-sources/xjc以下のjavaファイルをインポートして
利用しているのでjarが使用可能か未確認です。)


●signerの実装
2009年8月15日以降、Product Advertising APIは、リクエストに署名認証を含めなければならなくなりました。

下記にAmazonの提供している署名のサンプルがあります。
 Java Sample Code for Calculating Signature Version 2 Signatures


このサンプルのままでは、リクエストに改行が入ってしまって動かないので、
 76行目の
 Base64 encoder = new Base64();
を
  Base64 encoder = new Base64(0);
に変更する必要があります。

それと、日本での検索をしたい場合は、
 33行目 endpoint を "ecs.amazonaws.jp"に変更します。


 ●取得してみる
 作成したjar、signerをインポートしてjerseyを利用して検索結果をそのまま表示する
 サンプルを作ってみます。

src/main/java/gauuud/amazon/service/ItemSearchResource.java

package gauuud.amazon.service;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.amazon.associates.sample.SignedRequestsHelper;
import com.sun.jersey.api.client.Client;
import com.amazon.webservices.awsecommerceservice._2011_08_01.ItemSearchResponse;

@Path("/item_search")
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public class ItemSearchResource {
    @GET
    public ItemSearchResponse get(String word) throws Exception {

        SignedRequestsHelper signer = new SignedRequestsHelper();
       
        Map map = new HashMap();
        map.put("Service","AWSECommerceService");
        map.put("Operation","ItemSearch");
        map.put("Version","2011-08-01");
        map.put("SearchIndex","Books");
        map.put("Keywords","java");
       
        map.put("AssociateTag","[アソシエートID]");
       
        String url = signer.sign(map);
       
        Client c = Client.create();           

        ItemSearchResponse result = c.resource(url).get(ItemSearchResponse.class);

        return result;
    }
}



pom.xml  //いらないものが過分に含まれています。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>gauuud</groupId>
  <artifactId>aws-sample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>aws-sample</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
  <dependency>
   <groupId>org.codehaus.jettison</groupId>
   <artifactId>jettison</artifactId>
   <version>1.3</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-core</artifactId>
   <version>1.11</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-client</artifactId>
   <version>1.11</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-server</artifactId>
   <version>1.11</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-servlet</artifactId>
   <version>1.11</version>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-json</artifactId>
   <version>1.11</version>
  </dependency>
  </dependencies>
  <build>
   <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
       <version>8.0.0.v20110901</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webAppSourceDirectory>${basedir}/webapp</webAppSourceDirectory>
          <webXmlFile>${basedir}/webapp/WEB-INF/web.xml</webXmlFile>
          <contextPath>/</contextPath>
          <connectors>
            <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
              <port>8080</port>
              <maxIdleTime>60000</maxIdleTime>
            </connector> 
          </connectors>
          <systemProperties>
            <systemProperty>
              <name>org.apache.commons.logging.Log</name>
              <value>org.apache.commons.logging.impl.SimpleLog</value>
            </systemProperty>
          </systemProperties>
        </configuration>
      </plugin>      
      <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
   <configuration>
    <source>6</source>
    <target>6</target>
   </configuration>
      </plugin>
   </plugins>
  </build>
</project>
 
 
src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 version="3.0">
 <display-name>aws-sample</display-name>
     <welcome-file-list>
      <welcome-file>index.html</welcome-file>
     </welcome-file-list>

 <servlet>
  <servlet-name>jersey</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
   <param-name>com.sun.jersey.config.property.packages</param-name>
   <param-value>gauuud.amazon.service</param-value>
  </init-param>
  
        <load-on-startup>10</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>jersey</servlet-name>
  <url-pattern>/rest/*</url-pattern>
 </servlet-mapping>
 
</web-app>

maven jettry:run
を実行して
localhost:8080/rest/search_item
にアクセスするとxmlが取得できるはず。

2011年12月15日木曜日

Jersey Client 利用時の文字化け on CentOS5

Sakura VPS 上でJersey Client API を使った、
JSONを取得して、加工、受け渡しするようなRESTful APIを作成していたときに
文字化けが発生しました。

すべてUTF-8で統一されているのになぜ?とあせりました。
Java内部の問題なのかとも思いましたが、開発環境のUbuntuでは
発生してなかったので、ない。

受信周りの問題だなといろいろ調べた結果、
結局はロケールの設定の問題でした。
開発環境のUbuntuでは、

$ locale

の結果が、

$ locale
LANG=ja_JP.utf8
LC_CTYPE="ja_JP.utf8"
LC_NUMERIC="ja_JP.utf8"
LC_TIME="ja_JP.utf8"
LC_COLLATE="ja_JP.utf8"
LC_MONETARY="ja_JP.utf8"
LC_MESSAGES="ja_JP.utf8"
LC_PAPER="ja_JP.utf8"
LC_NAME="ja_JP.utf8"
LC_ADDRESS="ja_JP.utf8"
LC_TELEPHONE="ja_JP.utf8"
LC_MEASUREMENT="ja_JP.utf8"
LC_IDENTIFICATION="ja_JP.utf8"
LC_ALL=

のようになっているのに対してCentOSは、

$ locale
LANG=C
LC_CTYPE="C"
…

 C…、よくわからない値が入っていました。
なので、localeを編集 して、再起動しました。

$ vi /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"


結果、JSON取得時の文字化けはなくなりました。
Jerseyは賢い子

2011年12月8日木曜日

MavenのJDKバージョン設定

激しく構成が乱れてるけど、とりあえず公開しておきます。
そのうち直します。


Mavenでコンパイルエラーが発生しました。


注釈は -source 1.3 でサポートされていません
(注釈を使用可能にするには、-source 5 以降を使用してください)
    @Override

MavenのデフォルトでJDK1.3を使用しているために発生しているようです。
JDK1.3だと注釈、型指定のリスト、Foreach等が使えず割と不便。
 JDKを変更するためにはpom.xmlのpluginに次の項を追加します。


 <build>
 <properties>
  <java.version>1.6</java.version>
 </properties>
 
 <plugins>
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>2.3.2</version>
   <configuration>
    <source>${java.version}</source>
    <target>${java.version}</target>
   </configuration>
  </plugin>
 
参考
https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html

2011年10月27日木曜日

maven: jetty plugin ssl オレオレ証明書 の設定

jetty plugin 8.x での設定

1.keystore の作成
JDKのkeytoolでkeystoreを作成する。

keytool -keystore keystore -alias jetty -genkey -keyalg RSA -storepass (pass) -keypass (pass) -dname "CN=(domain)"


作成されたkeystoreを任意の場所へ


2.pom.xmlの編集
下記のようにpom.xmlにJetty pluginの設定を編集。
jetty-maven-pluginの"<connectors>"にSslSocketConnectorを追加する。

<connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector">
            <port>8443</port>
            <maxIdleTime>60000</maxIdleTime>
            <keystore>(任意のkeystoreへのパス)</keystore>
            <password>(pass)</password>
            <keyPassword>(pass)</keyPassword>
      </connector>


3.パスワードの暗号化
pom.xmlにパスワードを平文で保存するのは良くないので、
暗号化する。
java -cp jetty-http-8.x.jar:jetty-util-8.x.jar org.eclipse.jetty.http.security.Password (pass)


を実行すると、(pass)->jetty6の場合
jetty6
OBF:1ktv1x0r1z0f1z0f1x1v1kqz
MD5:e032a01e5c4dbb03a29fb031f6b37658


というような値が取得できるので、OBFまたはMD5をpom.xmlに入力する。





ついでに、iPhone等の開発でオレオレ証明書を利用する場合は、
NSURLRequestなら次のようなimplementの追加

@implementation NSURLRequest(NSHTTPURLRequest)

+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host
{
   return YES; // Or whatever logic
}
@end


ASIHttpRequestならvalidatesSecureCertificate = NOでOK