読者です 読者をやめる 読者になる 読者になる

帝国データバンクをスクレイピング

企業名と表示ページを指定して帝国データバンクに存在する企業を検索し、結果をJSONで返却するミニアプリ。
このアプリ自体は受け取ったクエリをそのまま帝国データバンクに渡すだけなため、利用する場合は帝国データバンクに過度の負荷をかけないよう、キャッシング等をクライアント側で適切に実装する必要があります。

ソースコードとしてはapp.jsとtdb.jsだけ見れば良いです。

帝国データバンク検索node

OpenShiftを使ってみる - 3

OpenShiftを使ってみる、第三弾としてOpenShiftにアプリケーションをデプロイする方法をまとめます。
JBoss ASを利用した場合の一通りの導入はまとめたと思っているので、一旦このシリーズは終了です。

方法として大きく2種類あります。開発スタイルや好みに応じて選んでください。

  • ソースコードをOpenShiftにPushして、OpenShift上でビルド&デプロイ
  • 予めビルドしたものをOpenShiftにPushしてデプロイ

また、どちらの方法でもOpenShiftに対してPushを行うと以下のような挙動を行います。

  1. JBossの停止
  2. .openshift/action_hooks/pre-build.sh実行
  3. 「openshift」プロファイルでmavenのビルド実行
  4. .openshift/action_hooks/build.sh実行
  5. .openshift/action_hooks/deploy実行
  6. JBossの開始
  7. .openshift/action_hooks/post_deploy実行

ソースコードをOpenShiftにPushして、OpenShift上でビルド&デプロイ

OpenShiftではビルドにMavenを利用します。そのため、pom.xmlが必要になりますが、OpenShiftからCloneしたリポジトリにはWARプロジェクト用のpom.xmlがあります。
WARで開発を行う場合は、このpom.xmlをもとにして開発を行うと容易にOpenShiftでのビルドとデプロイが可能です。

EARの場合、pom.xmlを別途作成する必要があります。
ポイントはEARパッケージのpom.xmlに以下のような設定を加え、deploymentsフォルダにEARファイルを出力させることです。

    <profile>
      <id>openshift</id>
      <build>
        <finalName>ROOT</finalName>
        <plugins>
          <plugin>
            <artifactId>maven-ear-plugin</artifactId>
            <version>2.6</version>
            <configuration>
              <version>6</version>
              <defaultLibBundleDir>lib</defaultLibBundleDir>
              <outputDirectory>deployments</outputDirectory>
              <modules>
                <webModule>
                  <groupId>groupId</groupId>
                  <artifactId>artifactId</artifactId>
                  <contextRoot>/</contextRoot>
                </webModule>
                <ejbModule>
                  <groupId>groupId</groupId>
                  <artifactId>artifactId</artifactId>
                </ejbModule>
              </modules>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>

予めビルドしたものをOpenShiftにPushしてデプロイ

この方法では予めビルドしておいたアプリケーションをOpenShiftにデプロイします。
GitやMavenを利用しない開発ではこの方法が良いかもしれません。

まずは誤ってビルドが実行されないように、以下を削除します。

次にデプロイ対象をdeploymentsに配置します。
そしてコミットを行いPushを行うことでデプロイします。

以下はこの方法を用いた場合のリポジトリディレクトリ構成となります。

├── .gitignore
├── .openshift
│   ├── action_hooks
│   │   ├── build
│   │   ├── deploy
│   │   ├── post_deploy
│   │   └── pre_build
│   ├── config
│   │   ├── modules
│   │   │   └── README
│   │   └── standalone.xml
│   ├── cron
│   │   ├── README.cron
│   │   ├── daily
│   │   │   └── .gitignore
│   │   ├── hourly
│   │   │   └── .gitignore
│   │   ├── minutely
│   │   │   └── .gitignore
│   │   ├── monthly
│   │   │   └── .gitignore
│   │   └── weekly
│   │       ├── README
│   │       ├── chrono.dat
│   │       ├── chronograph
│   │       ├── jobs.allow
│   │       └── jobs.deny
│   └── markers
│       └── README
├── README
└── deployments
    ├── .gitkeep
    └── ROOT.war

OpenShiftを使ってみる - 2

OpenShiftのアカウント登録からデプロイ用リポジトリのCloneまでが前回の手順ですが、今度はDBの作成を行います。

コマンドラインクライアントツールの導入(必要であれば)

公式ドキュメントを参照のこと
http://docs.redhat.com/docs/en-US/OpenShift/2.0/html-single/Getting_Started_Guide/index.html

OpenShiftClientToolをインストールする

#(その1をクリアしているならきっと入ってる…!)
$ sudo apt-get install git-core

# Rubyインタプリタを入れる。自力コンパイルでもRVMでも何でも良い。
$ sudo apt-get install ruby1.9.1
$ sudo apt-get install rubygems

# RubyGemでOpenShiftClientToolを入れる。
# sudoは環境に応じて。
$ sudo gem install rhc

rhcコマンドのPATHが通っていなければ~/.profile or ~/.bash_profileに追記

vi .profile
export PATH=/var/lib/gems/1.8/bin:$PATH

データベースを追加する(PostgreSQL8.4)

コンソール画面からアプリケーションを選択する。

「Add +」よりカートリッジの追加画面へ。

PostgreSQL Database 8.4」を選択する。

「Add Catridge」でカートリッジを追加する。

完了画面が表示されるので、接続情報などを確認する。
また、OpenShiftクライアントコンソールでのPostgreSQLの操作方法もあるのであわせて確認する。

You can get a list of cartridges by running

rhc app cartridge list

You can manage the cartridge by running one of these commands

rhc app cartridge start -a $APP_NAME -c postgresql-8.4
rhc app cartridge stop -a $APP_NAME -c postgresql-8.4
rhc app cartridge restart -a $APP_NAME -c postgresql-8.4
rhc app cartridge reload -a $APP_NAME -c postgresql-8.4
rhc app cartridge status -a $APP_NAME -c postgresql-8.4

You can remove the cartridge by running the following command.
Warning: make sure you've backed up any data you wish to keep before running this command

rhc app cartridge remove -a $APP_NAME -c postgresql-8.4

JBossのデータソース設定を確認する

OpenShiftからクローンしたデプロイ用のローカルリポジトリに移動する。

cd $LOCAL_REPO/.openshift/config
vi standalone.xml

すぐに利用できる形でデータソースが設定されている。必要に応じてJNDI名を変更等する。
環境変数はOpenShift側ですでに持っているため、このままで動作する。

<datasource jndi-name="java:jboss/datasources/PostgreSQLDS" enabled="${postgresql.enabled}" use-java-context="true" pool-name="PostgreSQLDS" use-ccm="true">
  <connection-url>jdbc:postgresql://${env.OPENSHIFT_DB_HOST}:${env.OPENSHIFT_DB_PORT}/${env.OPENSHIFT_GEAR_NAME}</connection-url>
  <driver>postgresql</driver>
  <security>
    <user-name>${env.OPENSHIFT_DB_USERNAME}</user-name>
    <password>${env.OPENSHIFT_DB_PASSWORD}</password>
  </security>
</datasource>

これでDBの利用準備が完了しました。

OpenShiftを使ってみる - 1

RedHatによるPaaSサービス、「OpenShift」を始めるための手順をメモとして残します。
まずは第1段としてOpenShiftのアカウントの作成から環境の作成、リポジトリのCloneまでを行います。

事前準備

  • SSH公開鍵の準備
  • Gitの導入

アカウント作成

「TRY IT NOW」でアカウント作成へ進みます

必要な情報を入力してアカウントを作成します。Promotional Codeは省略できます。

メールが送られるので待ちます。

メールのリンクを押すとログイン画面が表示されるのでログインします。

環境の作成

管理コンソールが表示されます。ここではJBoss AS7を作るので、「JBoss Application Server 7.1」をクリックします。

ネームスペースとアプリケーション名を指定します。ネームスペースはアカウントにつき1つです。後から変えることもできます。

しばらくたつと環境が出来上がるので、今度はSSHの公開鍵を登録します。

リポジトリのClone

画面中央辺りにGitのCloneコマンドが表示されるので、Cloneします。仕組みとしてはここでCloneしたリポジトリに修正をCommitし、Pushすることでデプロイする形になります。
また、このリポジトリにはOpenShift用の設定やスクリプト等が含まれています。

これでアプリケーションを開発する準備ができました。

Janetter検索ポップアップの検索エンジンを変更する

Janetterでは文字列選択時のポップアップによる検索についてはプラグインにて実現しているようです。
検索エンジンをYahooから変更したい場合、そのプラグインを書き換えてあげれば検索エンジンを変更できます。
もともと日本語圏以外はGoogleを利用する設定のようですので、日本語圏用の処理をコメントアウトするだけです。
なお、変更するかどうかは各個人で判断をお願いします。

C:\Program Files\Janetter2\Theme\Common\js\plugins\searchpopup.js

修正前

function getLink(selection) {
    //
    // Janetterの開発は皆さまのYahoo!検索によって支えられております。ありがとうございます!
    //
    if((jn.conf && jn.conf.lang ? jn.conf.lang : 'ja')=='ja'){
        return 'http://search.yahoo.co.jp/search?ei=UTF-8&fr=sb-jane&p=' + encodeURIComponent(selection);
    }else{
        return 'http://www.google.com/search?ie=UTF-8&oe=UTF-8&q=' + encodeURIComponent(selection);
    }
}

修正後

function getLink(selection) {
    //
    // Janetterの開発は皆さまのYahoo!検索によって支えられております。ありがとうございます!
    //
    /*
    if((jn.conf && jn.conf.lang ? jn.conf.lang : 'ja')=='ja'){
        return 'http://search.yahoo.co.jp/search?ei=UTF-8&fr=sb-jane&p=' + encodeURIComponent(selection);
    }else{
    */
        return 'http://www.google.com/search?ie=UTF-8&oe=UTF-8&q=' + encodeURIComponent(selection);
    //}
}

Janetterの「Yahoo! 検索」をGoogleに変更する

JanetterのWeb検索エンジン変更第2弾。
右クリック時の「Yahoo!で検索」をGoogleでの検索に変更する方法です。
表示用のリソースファイルja.jsonと検索処理用のapi.jsを変更します。

1.C:\Program Files\Janetter2\bin\locale\ja.jsonを変更する

修正前
"webSearch":"Yahoo! 検索",
修正後
"webSearch":"Google 検索",

2.C:\Program Files\Janetter2\Theme\Common\js\janet\api.jsを変更する

修正前
//------------------------------------------------
// Web検索のURL取得
//------------------------------------------------
jn.webSearchUrl = function(word){
	var url;
	word = encodeURIComponent(word);
	if(jn.conf.lang=='ja')
		url = jn.YAHOOCOJP_SEARCH_URI.format(word);
	else
		url = jn.GOOGLE_SEARCH_URI.format(word);
	return url;
};
修正後
//------------------------------------------------
// Web検索のURL取得
//------------------------------------------------
jn.webSearchUrl = function(word){
	var url;
	word = encodeURIComponent(word);
        //if(jn.conf.lang=='ja')
	//	url = jn.YAHOOCOJP_SEARCH_URI.format(word);
	//else
		url = jn.GOOGLE_SEARCH_URI.format(word);
	return url;
};

JSF2+CDI+Twitter4Jでカンバセーション内でOAuth認証を行う

個人的にハマりどころがあったのでJSF2+CDI+Twitter4JでのOAuth認証の方法をポイントだけまとめます。
JBoss7.1.0と7.1.1、GlassFish3.1.2で動作の確認をしています。

Twitterインスタンスを提供します。
TwitterFactoryはスレッドセーフのようなので共有し、Twitterをセッションに供給します。

@ApplicationScoped
public class TwitterProducer {
    
    private TwitterFactory twitterFactory = new TwitterFactory();
    
    @SessionScoped
    @Produces
    protected Twitter getTwitter() {
        return twitterFactory.getInstance();
    }
}

供給されたTwitterを利用してTwitterの認証系処理を行います。
状態を持つ必要はないのでステートレスにしています。

@Stateless
public class TwitterOAuthService {

    @Inject
    private Twitter twitter;

    /**
     * Twitter認証用URLを取得する
     */
    public RequestToken getRequestToken(String callbackURL) throws TwitterException {
        RequestToken requestToken = twitter.getOAuthRequestToken(callbackURL);
        return requestToken;
    }

    /**
     * Twitter認証のCallback処理を受け取る
     */
    public AccessToken callback(RequestToken requestToken, String verifier) throws TwitterException {
        return twitter.getOAuthAccessToken(requestToken, verifier);
    }
}

ログイン開始の処理です。
カンバセーションを開始してIDを取得するのがポイントです。
また、RequestTokenをカンバセーションにアウトジェクトしてコールバック時に備えます。
RequestTokenをカンバセーションに入れているのは、コールバックしたときに使いたいけれども、
セッションに入れても今後使わないだろうという推測からです。
Weld(CDIの実装)では現在カンバセーション開始した後のリダイレクトに問題があるようなので無理やりリダイレクトをかける必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">

    <h:form>
        <fieldset>
            <legend>ログイン</legend>
            <h:commandButton value="ログイン" action="#{loginAction.login()}" />
        </fieldset>
    </h:form>
</html>
@Named
@ConversationScoped
public class LoginAction implements Serializable {

    @Inject
    private TwitterOAuthService twitterLoginSrv;
    @Produces
    private RequestToken requestToken;
    @Inject
    private Conversation conversation;

    public void login() throws TwitterException, IOException {
        
        conversation.begin();
        
        ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
        
        String callbackURL = extCtxt.getRequestScheme()
                + "://"
                + extCtxt.getRequestServerName()
                + ":"
                + extCtxt.getRequestServerPort()
                + extCtxt.getRequestContextPath()
                + "/faces/callback.xhtml?cid=" + conversation.getId();

        requestToken = twitterLoginSrv.getRequestToken(callbackURL);

        // カンバセーションを開始すると外部サイトのリダイレクトがおかしくなる
        // https://issues.jboss.org/browse/WELD-1044
        // https://community.jboss.org/thread/180205
        // 
        // extCtxt.redirect(requestToken.getAuthenticationURL());

        Object obj = extCtxt.getResponse();
        if (obj instanceof HttpServletResponse) {
            HttpServletResponse response = (HttpServletResponse) obj;
            // ExternalContext.redirectと同じ結果になる。
            //response.sendRedirect(response.encodeURL(requestToken.getAuthenticationURL()));
            response.setHeader("Location", response.encodeRedirectURL(requestToken.getAuthenticationURL()));
            response.setStatus(HttpServletResponse.SC_SEE_OTHER);
            response.getWriter().flush();
        }
    }
}

コールバックを受け取る処理です。
ポイントはviewParamを用いてGETのパラメータを取り出し、preRenderViewで処理する点です。
また、ログイン開始と同じカンバセーションになるため、RequestTokenを取り出して使います。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    
    <h:head>
        <f:metadata>
            <f:viewParam name="#{callbackAction.oauthVerifierName}"
                         value="#{callbackAction.oautuVerifierValue}"
                         required="true"
                         requiredMessage="Error"/>
            <f:event type="preRenderView"
                     listener="#{callbackAction.callback()}"/>
        </f:metadata>
    </h:head>
    <h:body>
    </h:body>
</html>
@Named
@ConversationScoped
public class CallbackAction implements Serializable {

    @Inject
    private TwitterOAuthService twitterLoginSrv;
    @Inject
    private RequestToken requestToken;
    private String oauthVerifierName = "oauth_verifier";
    private String oautuVerifierValue;
    @Inject
    private Conversation conversation;

    public void callback() throws TwitterException {
        twitterLoginSrv.callback(requestToken, getOautuVerifierValue());
        conversation.end();
    }

    public String getOauthVerifierName() {
        return oauthVerifierName;
    }

    public String getOautuVerifierValue() {
        return oautuVerifierValue;
    }

    public void setOautuVerifierValue(String oautuVerifierValue) {
        this.oautuVerifierValue = oautuVerifierValue;
    }
}

あとはbeans.xmlやtwitter4j.propertiesに注意。