Herokuにアクセスする為に、rbenv でruby環境を作成した



Herokuにアクセスし、操作するために、「heroku toolbelt」というものがある
CLI toolとして利用するものみたいですが、動かない環境があるという事例をブログで拝見した

そこで、今回は、rubyのgemで管理されているherokuをインストールし利用しようと思う
 

今回のチャレンジ

 

環境

 

rbenvのインストール

rbenvは、「Simple Ruby Version Management」のことである
くわしくは、READMEを参照してください
特にRubyバージョン切り替えが必要なわけではなかったが、なんとなく試したかったのでインストールしてみました
ruby-buildは、「Compile and install Ruby」のことである
くわしくは、READMEを参照してください

git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
vi .bash_profile
 export PATH=$HOME/.rbenv/bin:$PATH
 eval "$(rbenv init -)"
 source .bash_profile

git clone git://github.com/sstephenson/ruby-build.git
cd ruby-build
sudo ./install.sh

 
「rbenv install」コマンドで、インストール可能なRubyのバージョン一覧が表示されるか確認を行う

usage: rbenv install VERSION
       rbenv install /path/to/definition

Available versions:
  1.8.6-p383
  1.8.6-p420
  1.8.7-p249
  1.8.7-p302
  1.8.7-p334
  1.8.7-p352
  1.8.7-p357
  1.9.1-p378
  1.9.2-p180
  1.9.2-p290
  1.9.3-dev
  1.9.3-p0
  1.9.3-preview1
  1.9.3-rc1
  2.0.0-dev
  jruby-1.6.3
  jruby-1.6.4
  jruby-1.6.5
  jruby-1.6.5.1
  jruby-1.6.6
  jruby-1.7.0-dev
  maglev-1.0.0
  rbx-1.2.4
  rbx-2.0.0-dev
  ree-1.8.6-2009.06
  ree-1.8.7-2009.09
  ree-1.8.7-2010.01
  ree-1.8.7-2010.02
  ree-1.8.7-2011.03
  ree-1.8.7-2011.12

 
とりあえず、Rubyをインストール準備までできました
 

Ruby 1.9.3-p0 をインストールする

rbenvのコマンドを利用して、インストールしたいRubyのバージョンを選択します

rbenv install 1.9.3-p0
rbenv global 1.9.3-p0
rbenv rehash
ruby -v
 ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]

 

gem で heroku をインストールする

Rubyが利用できるようになったので、gemでherokuをインストールします

gem update --system
gem install heroku
heroku version
 heroku-gem/2.20.1

 
「heroku version」とうって、バージョンが出力されればherokuコマンドが
利用できます
 

Play framework 2.0 RC2 を heroku で試してみた



scalaで利用できるWEBフレームワークで、なにかないかと思い探してみた
丁度、Play frameworkの新しいものがリリースされそうだったので試してみた
 

試してみようとおもった動機

  • scalaが利用できる
  • SBT(Simple Build Tools)ベースで開発ができる
  • Railsのようなプロジェクト構成

 

環境

 

Play framework 2.0 RC2のインストール

事前に、Java SDKScala の実行環境を作成しておく
 

play-2.0-RC2.zipをダウンロードする

play-2.0-RC2.zipを取得し、展開する

wget http://download.playframework.org/releases/play-2.0-RC2.zip
unzip play-2.0-RC2.zip

 
.bash_profileにplay-2.0のホームを設定する

vi .bash_profile
export PLAY_HOME=/home/user/play-2.0-RC2
export PATH=$PATH:$PLAY_HOME
source .bash_profile

 
Playの環境ができているかコンソールから確認をしてみる*1

$ play help

       _            _
 _ __ | | __ _ _  _| |
'_ \ / _' _
__/ _ \____ \__ (_)
_ __/
play! 2.0-RC2, http://www.playframework.org Welcome to Play 2.0! These commands are available:
                                                        • -
license Display licensing informations. new Create a new Play application in the current directory. You can also browse the complete documentation at http://www.playframework.org.

 

試しにサンプルプロジェクトを作成してみる

「play new」コマンドでサンプルプロジェクトを作成してみた

$ play new play20_rc2sample
Getting net.java.dev.jna jna 3.2.3 ...
retrieving :: org.scala-tools.sbt#boot-app
confs: [default] 1 artifacts copied, 0 already retrieved (838kB/10ms) Getting Scala 2.9.1 (for console)...
retrieving :: org.scala-tools.sbt#boot-scala
confs: [default] 4 artifacts copied, 0 already retrieved (19939kB/34ms) Getting play console_2.9.1 2.0-RC2 ...
retrieving :: org.scala-tools.sbt#boot-app
confs: [default] 5 artifacts copied, 0 already retrieved (5763kB/13ms) _ _ _ __ | | __ _ _ _| |
'_ \ / _' _
__/ _ \____ \__ (_)
_ __/
play! 2.0-RC2, http://www.playframework.org The new application will be created in /home/user/play20_rc2sample What is the application name? > play20_rc2sample Which template do you want to use for this new application? 1 - Create a simple Scala application 2 - Create a simple Java application 3 - Create an empty project > 1 OK, application play20_rc2sample is created. Have fun!

 
サンプルプロジェクトのアプリケーションを実行してみる
サンプルプロジェクトのディレクトリ直下で、sbtを「play」コマンドで実行する
その後、「run」コマンドでアプリケーションを起動する

$cd play20_rc2sample
$play
Getting org.scala-tools.sbt sbt_2.9.1 0.11.2 ...
retrieving :: org.scala-tools.sbt#boot-app
confs: [default] 37 artifacts copied, 0 already retrieved (7324kB/54ms) [info] Loading project definition from /home/user/play20_rc2sample/project [info] Set current project to play20_rc2sample (in build file:/home/user/play20_rc2sample/) _ _ _ __ | | __ _ _ _| |
'_ \ / _' _
__/ _ \____ \__ (_)
_ __/
play! 2.0-RC2, http://www.playframework.org > Type "help play" or "license" for more information. > Type "exit" or use Ctrl+D to leave this console. $ run [info] Updating {file:/home/user/play20_rc2sample/}play20_rc2sample... [info] Done updating. (Running the application from SBT, auto-reloading is enabled) --- [info] play - Listening for HTTP on port 9000... (Server started, use Ctrl+D to stop and go back to the console...) [info] Compiling 5 Scala sources and 1 Java source to /home/user/play20_rc2sample/target/scala-2.9.1/classes... [info] play - Application started (Dev)

 
http://ip address:9000/ などにアクセスしてみると「Welcome to Play 2.0」というトップページが確認できる
 

herokuで実行してみる

herokuに作成したサンプルアプリケーションをデプロイし、実行してみます
 

環境
  • gemかなにかでherokuコマンドが利用できるようにしておく
$ heroku version
heroku-gem/2.20.1

 

herokuにデプロイする

Procfileファイルを作成する
詳しくは、About the Celadon Cedar Stackをどうぞ

cd /home/user/play20_rc2sample
vi Procfile
web: target/start -Dhttp.port=${PORT} ${JAVA_OPTS} -DapplyEvolutions.default=true

 
project/plugins.sbtに「xsbt-start-script-plugin」というプラグインを追加する 

cd /home/user/play20_rc2sample
vi ./project/plugins.sbt
addSbtPlugin("com.typesafe.startscript" % "xsbt-start-script-plugin" % "0.5.0")

 
herokuに登録するために、ローカルのgitに登録を行う

git init
Initialized empty Git repository in /home/user/play20_rc2sample/.git/
git add .
git commit -m "init"

 
Cedar Stack でアプリケーションを作成する
その後、プロセスを起動する

heroku create --stack cedar
heroku scale web=1

 
gitからherokuへデプロイを行う

git push heroku master

          • > Discovering process types
Procfile declares types -> web
          • > Compiled slug size is 79.4MB
          • > Launching... done, v5
http://xxxx-xxxx-xxx.herokuapp.com deployed to Heroku

 
herokuコマンドで動作確認をする
「heroku ps」で該当プロセスが存在しているか確認する
「heroku logs」で実行アプリケーションにエラーがないか確認する

$ heroku ps
Process  State       Command
------- ---------- ------------------------------------
web.1 up for 18s target/start -Dhttp.port=${PORT} $.. $ heroku logs 2012-02-xxTxx:xx:02+00:00 heroku[router]: GET xxxx-xxxx-xxx.herokuapp.com/ dyno=web.1 queue=0 wait=0ms service=236ms status=200 bytes=498 2012-02-xxTxx:xx:03+00:00 heroku[router]: GET xxxx-xxxx-xxx.herokuapp.com/assets/stylesheets/main.css dyno=web.1 queue=0 wait=0ms service=133ms status=200 bytes=0 2012-02-xxTxx:xx:03+00:00 heroku[router]: GET xxxx-xxxx-xxx.herokuapp.com/assets/javascripts/jquery-1.7.1.min.js dyno=web.1 queue=0 wait=0ms service=34ms status=200 bytes=93868

 
http://xxxx-xxxx-xxx.herokuapp.com/にアクセスし、サンプルページがみえるか確認をする。
 

課題

herokuで実行した際に、「./app/views/main.scala.html」から読み込まれている「./app/views/index.scala.html」が
うまく読み込まれていないようだった。時間がある時に調整してみる
 

*1: playのロゴが崩れていますが気にしないで下さい。

OAuth2.0によるGoogle+ APIを試す



最近、Twitterのツイート情報をローカルに保存するために、OAuth1.0を調べていた。
CONSUMER_KEY、CONSUMER_SECRET、リクエストークン、ACCESS_TOKENなど実際に自分で
試してみるまでよく意味が分からなかった。
たまたま購読しているメールで、「OAuth2.0によるGoogle+ APIのアクセス方法」という情報が
あったので、OAuth2.0ではどのようにアクセスすれば良いのか試してみた。
Google Social Developers Japan
 

参考にした情報

OAuth2.0によるGoogle+ APIのアクセス方法
Google API Expert (Social)の方の記事をそのまま参考にさせて頂きました。
WEB+DB PRESS Vol.63
OAuthの特集記事があったので、基本的な概念と1.0 と 2.0のそれぞれの違いを確認しました。
 

試したこと(事前準備)

 事前準備:Google+にアカウントがあること
 

試したこと(事前準備)

1. Client IDの発行

OAuthで利用するための情報を発行します。
https://code.google.com/apis/console/ から登録を行いましょう。

Client ID for web applications

Client id:hogehage.apps.googleusercontent.com
Client secret:************************
Redirect URIs:http://localhost/oauth2callback
JavaScript origins:http://localhost

 
2. ユーザの認可

ServiceProviderにConsumerを登録しましょう。(OAuth2.0でも同じ役割かわかりません)

https://accounts.google.com/o/oauth2/auth?client_id=[YOUR client_id]&redirect_uri=[CALLBACK URL]&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.me&response_type=code

 
redirect_uriとscopeの値はURIエンコードをする。
上記のURLをブラウザで参照すると下記のような感じで表示がされます。

http://[CALLBACK URL]/oauth2callback?code=********

 
codeがAuthorization code値というものになるようです。
 
3. アクセストークンの取得

curlコマンドを利用して、アクセストークンを取得します。

curl -d client_id=[YOUR Client Id] -d client_secret=[YOUR Client Secret] -d redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback -d grant_type=authorization_code -d code=[YOUR Authorization code] https://accounts.google.com/o/oauth2/token

 
コマンドラインからアクセスを行うと下記の様な情報が返信されます。

{"access_token":"***","token_type":"Bearer","expires_in":3600,"refresh_token":"***"}

 
4. APIを利用して、Google+にアクセスしてみる

認可ユーザ自身のユーザ情報

curl -H "Authorization: OAuth [YOUR Access_token]" https://www.googleapis.com/plus/v1/people/me

 

{
"kind": "plus#person",
"id": "***",
"displayName": "***",
"gender": "male",
"aboutMe": "",
"url": "https://plus.google.com/***",
"image": {
"url": "https://lh5.googleusercontent.com/***/photo.jpg"
},
"urls": [
{
"value": "https://plus.google.com/***",
"type": "profile"
},
{
"value": "https://www.googleapis.com/plus/v1/people/***",
"type": "json"
}
],
"organizations": [
{
"name": "",
"title": "",
"type": "work"
}
],
"placesLived": [
{
"value": ""
},
{
"value": "",
"primary": true
}
]
}

 
認可ユーザの一般公開のフィード一覧

curl -H "Authorization: OAuth [YOUR Access_token]" https://www.googleapis.com/plus/v1/people/me/activities/public

 

{
"kind": "plus#activityFeed",
"nextPageToken": "***",
"selfLink": "https://www.googleapis.com/plus/v1/people/**/activities/public?",
"nextLink": "https://www.googleapis.com/plus/v1/people/**/activities/public?maxResults=20&pageToken=**",
"title": "Plus Public Activity Feed for **",
"updated": "2011-09-13T04:56:33.092Z",
"id": "tag:google.com,2010:/plus/people/**/activities/public",
"items": [
{
"kind": "plus#activity",
"title": "最近、Scalaでいろいろ楽しんでる。",
"published": "2011-09-13T04:56:32.000Z",
"updated": "2011-09-13T04:56:33.092Z",
"id": "**",
"url": "https://plus.google.com/**",
"actor": {
"id": "**",
"displayName": "**",
"url": "https://plus.google.com/**",
"image": {
"url": "https://lh5.googleusercontent.com/**/photo.jpg"
}
},
"verb": "post",
"object": {
"objectType": "note",
"content": "最近、Scalaでいろいろ楽しんでる。",
"originalContent": "",
"url": "https://plus.google.com/**",
"replies": {
"totalItems": 0
},
"plusoners": {
"totalItems": 0
},
"resharers": {
"totalItems": 0
}
},
"provider": {
"title": "Google+"
},
"access": {
"kind": "plus#acl",
"items": [
{
"type": "public"
},
{
"type": "person",
"id": "**"
}
]
}
}
]
}

 
5. はまったこと

2のAuthorization code値を取得した後に、2時間程、放置してしまい「3. アクセストークンの取得」
を実施したところ下記のエラーがでた。

 {"error":"invalid_grant"}

 
Authorization code値には、有効期限があったようで、再度、Authorization code値を取得し、「3. アクセストークンの取得」を
実施したら正常にアクセストークンを取得できた。
 
「4. APIを利用して、Google+にアクセスしてみる」際に、https://www.googleapis.com/plus/v1/people/meアクセス時に
適切なヘッダー情報を付与しなかったら下記のようなエラーがでた。
curlコマンド

curl -H *** https://www.googleapis.com/plus/v1/people/me

 

{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit Exceeded. Please sign up",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit Exceeded. Please sign up"
}
}

 
エラーのメッセージからは、1日の利用制限に達したと読めたのだがyoichiro氏のOAuth2.0によるGoogle+ APIのアクセス方法
みると自分の発行したcurlコマンドからは、Authorization: OAuthというヘッダー情報が漏れていた。
 

今後

Google+ PlatformのAPIサイトにいろいろ情報が掲載されているので、いろいろ調べてみようと
思います。

https://developers.google.com/+/api/


Scientific Linux 6.1で作るサーバ環境 OSインストール



3月の年度末に、NTT-Xにて廉価版のサーバマシーンを購入しました。
検証用として購入したマシーンにLinuxをインストールしたので、その記録をここに残したいと思います。
インストールしたLinuxディストリビューションは、「Scientific Linux 6.1」になります。
Scientific Linux公式サイト
http://www.scientificlinux.org/
 

試した環境と構築方針

下記のサーバにKingston 8GB 1333MHz DDR3 ECC*1のメモリを追加しました。

項目内容
OSScientific Linux 6.1
ハードProLiant ML110 G6 (Core i3-530/2GB/SATA160GB)
基本方針サーバ向け最小構成 + 開発環境
 

  Intel VT が使えるか確認する。(はじめ、VMWare ESXi上でLinuxを管理しようと思いましたがやめました。)

 grep vmx /proc/cpuinfo
 flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat tpr_shadow vnmi flexpriority ept vpid
 flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat tpr_shadow vnmi flexpriority ept vpid
 flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat tpr_shadow vnmi flexpriority ept vpid
 flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat tpr_shadow vnmi flexpriority ept vpid

 

Scientific Linux 6.1のインストール

SL6.1(Scientific Linux 6.1)は、DVD版のisoイメージからインストールを行います。インストールする際のポイントを次にまとめます。

項目内容
ディスクパーティション手動設定
IPアドレス手動設定
パッケージカスタム
 

インストール予定ソフト一覧

一般的なLAMP(Apache/PHP/MySQL)環境を用意しようと思います。また、日頃気になっているソフトウェアを検証環境として
随時用意しようと思います。

項目バージョン内容
MRTGmrtg-2.16.2-5.el6.x86_64(rpm)ネットワークの負荷を監視するツール
Apache HTTP Serverhttpd-2.2.19.tar.gz Webサーバソフトウェア
MySQLmysql-5.5.15-linux2.6-x86_64.tar.gzオープン ソース データベース
PHPphp-5.3.8.tar.gzオープンソースの汎用スクリプト言語
JDKjdk-6u27-linux-x64-rpm.bin(rpm)Java アプリケーションおよびアプレット開発環境
Apache Antapache-ant-1.8.2-bin.tar.gzビルドツール
memcachedmemcached-1.4.7.tar.gz汎用の分散型メモリキャッシュシステム
Kyoto Cabinet、Kyoto Tycoonkyotocabinet-1.2.70.tar.gz、kyototycoon-0.9.51.tar.gz国産 KVS、時限削除機能付きの軽量データベースサーバ
Redmineredmine-1.1.0.tar.gzプロジェクト管理ソフトウェア
Apache Solrapache-solr-3.3.0.tgzオープンソース全文検索システム
Apache Tomcatapache-tomcat-7.0.19.tar.gzサーブレットJSPを実行するためのサーブレットコンテナ(サーブレットエンジン)
Subversionsubversion-1.6.11-2.el6_1.4.x86_64(rpm)バージョン管理システム
The Apache Cassandraapache-cassandra-0.8.4-bin.tar.gzオープンソースの分散データベース管理システム
 

パーティション構成

基本パーティション

項目内容
/boot200M
/15G
tmpfs5G
kdump31G
 
拡張パーティションLinux LVM
項目内容
/usr28G
/var30G
/home8G
/opt20G
/tmp5G
 

参考

Scientific Linux6.0のインストール〜その1〜
Linux技術トレーニング 基本管理コース II 第2章 ディスク管理〜上級
Linux-DB システム構築/運用入門 amazon.co.jp
 


*1: 気のせいか大分価格が高騰(2011/9/4)

scalaでOracle接続を試す



仕事で利用しているOracleScalaから接続してみた。ソースコードは、「Oracle11gをJDBCドライバを使ってScalaから操作」を参考にしております。
Oracleの10gに接続しております。(sshでポートフォワードしている為、127.0.0.1で接続しています。)

変更している点

  • package宣言を加えています
  • USER_OBJECTSをOBJECT_TYPEでカウントされるSQLに変えています。

Windowsコンパイルさせて、Windowsで動作させてみました。

 scalac -cp build/classes -d build/classes/ src/sample/SqlSelect.scala
 scala -cp build/classes;lib/classes12.zip sample.SqlSelect

 
scalacでコンパイルする際に、「-cp build/classes」は、特にいらないのですが付けてます。
Linux環境では、「-cp build/classes/」と最終文字に/を加えて上げないとエラーがでました。

Linux環境などで文字コードEUCだったりすると、「-encoding euc-jp」とつけてあげる必要があったりします。

package sample

import java.io.PrintWriter
import java.sql.{DriverManager, Connection, Statement, ResultSet,SQLException}

object SqlSelect {
  var jdbcURL = "jdbc:oracle:thin:@127.0.0.1:1521:schema"
  var user ="user"
  var passwd ="password"

  def main(args : Array[String]) : Unit = {
    
    val SQL_USER_OBJECT:String = 
      "SELECT OBJECT_TYPE, COUNT(OBJECT_TYPE) FROM USER_OBJECTS GROUP BY OBJECT_TYPE ORDER BY COUNT(OBJECT_TYPE)";
    val out = new PrintWriter("execute.log")
    try {
        Class.forName("oracle.jdbc.driver.OracleDriver").newInstance()
        var con = DriverManager.getConnection(jdbcURL,user,passwd)
        try {
           var stmt = con.createStatement()
           var rs = stmt.executeQuery(SQL_USER_OBJECT)
           while (rs.next()){
              print(rs.getString(1) + " ")
              println(rs.getString(2))
          }
          stmt.close()
      } catch {
         case e:SQLException => {
           println("Database error1 "+e)
           out.println("Database error1 "+e)
           out.close
         }
         case e => {
           println("Some other exception type:")
           e.printStackTrace()
         }
      } finally {
         con.close()
      }
   } catch {
      case e:SQLException => {
        println("Database error2 "+e)
        out.println("Database error2 "+e)
        out.close
      }
      case e => {
        println("Some other exception type:")
        e.printStackTrace()
     }
  }
 }
}

 
日常で普通にScalaが利用できるようになりたいです。
 


scalaでtwitter searchを試す



Scalaスケーラブルプログラミングを読みながらscalaソースコードをいろいろ試しています。

33章と量も多く、なかなか使いこなすのが難しいのでいろいろ試してみたいと思います。
 

「search.twitter」の内容を返すサンプルを試す

http://search.twitter.com/search?q=tenshoku」というサイトがあることを知りませんでした。「http://twitter.com/#!/search/tenshoku」とは違う検索結果を返すことに気づきました。

サンプルで利用させて頂いたコードはこちらです。HashTagSearch.scala
 

「HashTagSearch.scala」を実行する

Windows環境のコマンドプロンプトで実行をすると文字化けが起こったので、実行結果をFileに出力することにしました。
ローンパターン(loan pattern)というものもあるようだがとりあえず、Fileに出力できるようにしました。
(参考:How to write to a file in scala?

 import scala.xml._
 import scala.io.Source
 
 import java.io.PrintWriter
 
 object HashTagSearch2{
   
   def main( args:Array[String] ) {
     System.setProperty("http.proxyHost","proxy.host.jp")
     System.setProperty("http.proxyPort","8080")
     val out = new PrintWriter("sample.txt")
     val url =
       "http://search.twitter.com/search.atom?q=%s".format( args.first )
     ( XML.loadString(
         Source.fromURL( url, "utf-8").getLines.mkString) \\ "entry").
     foreach{
       e =>
         val cxml = XML.loadString("<c>" + (e \\ "content" text ) + "</c>")
         println( (e \\ "author" \\ "name" text)  + ":" + cxml.child.text)
         out.println((e \\ "author" \\ "name" text)  + ":" + cxml.child.text)
     }
     out.close
   }
 }

 
ブラウザで「http://search.twitter.com/search.atom?lang=ja&q=tenshoku」を押下すると
下記の様な検索結果が返却されます。HashTagSearchでは、entryタグを抽出し、抽出した要素に
対して「e =>処理」を実行しています。foreachでは、「content」を「c」に置き換えて処理を行ってます。
textは、タグを消してテキスト情報をそのまま出力する処理です。

 <entry>
  <id></id>
  <published></published>
  <link type="text/html" href="http://twitter.com/tenshokukango/statuses/80155039427072000" rel="alternate"/>
  <title></title>
  <content type="html"></content>
  <updated></updated>
  <link type="image/png" href="http://a0.twimg.com/profile_images/1381477303/kango_normal.gif" rel="image"/>
  <twitter:geo></twitter:geo>
    <twitter:metadata>
      <twitter:result_type>recent</twitter:result_type>
    </twitter:metadata>
  <twitter:source>&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;</twitter:source>
  <twitter:lang>ja</twitter:lang>
  <author>
   <name>tenshokukango (&#12511;&#12516;&#12499;)</name>
   <uri>http://twitter.com/tenshokukango</uri>
  </author>
</entry>

 
処理を実行すると下記の様な形で、「sample.txt」に保存されます。

tenshokukango (ミヤビ):知ってました?3年以上の病院勤務者であれば月収45万以上が確定します。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou
JimujobTokyoIn (CJ-都内事務求人):大手医薬品メーカーでのMRサポート事務のお仕事です http://dlvr.it/W6Kqq #kyujin #tenshoku
JimujobTokyoIn (CJ-都内事務求人):建築関連会社での社保事務・データ入力のお仕事です http://dlvr.it/W6KWT #kyujin #tenshoku
ITJobTokyoOut (CJ-東京都下IT求人):【IT求人】 <IBM>金融系 【PM/PL:Webアプリケーション開発】 http://dlvr.it/W6KkW #kyujin #tenshoku
Careerjet_jp (CJ-キャリアジェット):【求人】 【千葉県我孫子市】介護老人保健施設の常勤看護師募集☆少人数の利用者さんたちとの交流を望まれる看護師さんにお勧めです!【TS-CB093】 http://dlvr.it/W6KVp #kyujin #tenshoku
Careerjet_jp (CJ-キャリアジェット):【求人】 【千葉県鴨川市】医療から介護までトータルに施設が併設の地域完結型病院です!! 急性期から療養期までトータルにサポート可能で、精神病院や介護施設も併設している病院です!【TS-CB094】 http://dlvr.it/W6KT5 #kyujin #tenshoku
tenshokukango (ミヤビ):あなたの代わりに給料の交渉もしてくれます。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou
LEC_PROCAREER (LEC-procareer):【緊急募集】LECでは業務拡大により職業訓練(基金訓練)のクラス運営+就職支援業務担当者を大募集中!是非ご応募下さい! http://ht.ly/3OBib #shukatsu #syukatsu #syusyoku #shusyoku #tensyoku #tenshoku
tenshokukango (ミヤビ):期間を決めてリゾート気分を味わいながら看護師の仕事ができちゃうんです。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou
tenshokukango (ミヤビ):転職を考えています?このサイト知ってますか?あなたの代わりに病院との交渉をしてくれます。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou
tenshokukango (ミヤビ):実はもっと給料を貰えるって思っている人が少ないみたいです。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou
yamanekopanda (山 猫):RT @seseseico: 【仕事情報】博多駅近くで一般事務のお仕事。8:50〜17:10で残業ほとんどありません。7/1スタートで時給900円。過去5年間内で金融業界経験のある方お待ちしております。#haken #baito #tenshoku #kyujin
sexypon (ぽん):RT @seseseico: 【仕事情報】博多駅近くで一般事務のお仕事。8:50〜17:10で残業ほとんどありません。7/1スタートで時給900円。過去5年間内で金融業界経験のある方お待ちしております。#haken #baito #tenshoku #kyujin
ryonagai_sigoto (長井亮の仕事塾):「仕事」以外に、目に見えない仕事の報酬は自分にとってなんでしょうか? ##shukatsu #shushoku #tenshoku
tenshokukango (ミヤビ):自分が動かなければ何も変わらないんです。それは給料も同じですよ。http://amba.to/lOxxUU 月収45万!看護師の転職を探すなら登録無料のナースパワー #Tenshoku #kango #kangoshi #kyujin #muryou

もう少しいろいろ試して、Twitterで抽出した内容をDB等に保存できるようにしたいと思います。


さくらVPSでcassandra-0.8.0-beta1を試す



まだ、cassandra-0.7.4もきちんと理解していないのに、「devアットcassandra.apache.org」にて「[VOTE] Apache Cassandra 0.8.0-beta1」が
流れていたので、CQLを試したく、インストールしてみた。0.8.0-beta1 artifactsというところにお試しがあったのでインストールしてみました。

他のバージョンに関しては、こちらをご参考にしてください。

 

apache-cassandra-0.8.0-beta1-bin.tar.gzをインストール

0.6系、0.7系と同様に既存のサービスを止め、「/var/log/cassandra/」「/var/lib/cassandra/」に配置してある
ログデータやDBデータを削除しました。一点、「./conf/cassandra.yaml」の記述ではまり、cassandraサービスが
立ち上がりませんでした。
 

apache-cassandra-0.8.0-beta1のサービス起動時にエラー

サービス起動時に以下のエラーがでてしまい、「java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map」
と言われている。システムの環境変数に0.7.4の情報を設定していたのでその情報が悪さしているものと思い一通り綺麗に
してみたが、現象は変わりませんでした。

ERROR [main] 2011-04-19 xx:xx:xx,xxx DatabaseDescriptor.java (line 420) Fatal configuration error error
Can't construct a java object for tag:yaml.org,2002:org.apache.cassandra.config.Config; exception=Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@709446e4; java.lang.reflect.InvocationTargetException
 in "<reader>", line 10, column 1:
    cluster_name: 'Test Cluster'
    ^
        at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:372)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:177)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:136)
        at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:122)
        at org.yaml.snakeyaml.Loader.load(Loader.java:52)
        at org.yaml.snakeyaml.Yaml.load(Yaml.java:166)
        at org.apache.cassandra.config.DatabaseDescriptor.<clinit>(DatabaseDescriptor.java:139)
        at org.apache.cassandra.service.AbstractCassandraDaemon.setup(AbstractCassandraDaemon.java:98)
        at org.apache.cassandra.service.AbstractCassandraDaemon.activate(AbstractCassandraDaemon.java:314)
        at org.apache.cassandra.thrift.CassandraDaemon.main(CassandraDaemon.java:80)
Caused by: org.yaml.snakeyaml.error.YAMLException: Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@709446e4; java.lang.reflect.InvocationTargetException
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:305)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:184)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:370)
        ... 9 more
Caused by: org.yaml.snakeyaml.error.YAMLException: java.lang.reflect.InvocationTargetException
        at org.yaml.snakeyaml.constructor.Constructor$ConstructSequence.construct(Constructor.java:589)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:177)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:298)
        ... 11 more
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructSequence.construct(Constructor.java:587)
        ... 13 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
        at org.apache.cassandra.config.SeedProviderDef.<init>(SeedProviderDef.java:34)
        ... 18 more

 

apache-cassandra-0.8.0-beta1のソースにデバッグ情報を入れ、確認をしてみる

apache-cassandra-0.8.0-beta1-src.tar.gzをダウンロードし、「org.apache.cassandra.config.SeedProviderDef」クラスの
34行目を確認してみました。

public class SeedProviderDef
{
    public String class_name;
    public Map<String, String> parameters;
    
    public SeedProviderDef(LinkedHashMap p)
    {
        class_name = (String)p.get("class_name");
        parameters = (Map<String, String>)((List)p.get("parameters")).get(0);
    }
}

シンプルなソースで間違えるはずは無いのですが、「java.lang.String cannot be cast to java.util.Map」と言われてます。
SeedProviderDefクラスがどこで利用されているかというと、org.apache.cassandra.config.Configで利用されているようです。


0.7.4の時が、どんなソースだったかというと

   public String[] seeds;
    public DiskAccessMode disk_access_mode = DiskAccessMode.auto;

という感じでした。
ちなみに、0.8betaでは、下記の様な感じです。

    public SeedProviderDef seed_provider;
    public DiskAccessMode disk_access_mode = DiskAccessMode.auto;

 

SeedProviderDefを設定しているところを探す

「org.apache.cassandra.config.DatabaseDescriptor」クラスで初期化しているところを発見しました。

            TypeDescription seedDesc = new TypeDescription(SeedProviderDef.class);
            seedDesc.putMapPropertyType("parameters", String.class, String.class);
            constructor.addTypeDescription(seedDesc);

 
TypeDescriptionは、サードパーティライブラリのようです。「org.yaml.snakeyaml.TypeDescription」
読み込みも間違ってなさそうなので、ログを出力し、なにが格納されているかみてみることにしました。
 

cassandra-0.8.0-beta1のソースをビルドする

SeedProviderDefクラスの「p.get("parameters")」には、なにが入っているのかログを出力してみることにしました。
こんな感じです。

public class SeedProviderDef
{
    private static Logger logger = LoggerFactory.getLogger(SeedProviderDef.class);
    public String class_name;
    public Map<String, String> parameters;

    public SeedProviderDef(LinkedHashMap p)
    {
        logger.info("Start SeedProviderDef");
        class_name = (String)p.get("class_name");
        logger.info("aaa**:" + p);
        parameters = (Map<String, String>)((List)p.get("parameters")).get(0);
    }
}

Antがインストールされていれば、「Ant jar」でビルドすることができました。
build/apache-cassandra-0.8.0-beta1-SNAPSHOT.jarというファイルができたので、実行時のJarとして
入れ替えてみました。

すると。。

 INFO xx:xx:xx,xxx aaa**:127.0.0.1
ERROR xx:xx:xx,xxx Fatal configuration error error
Can't construct a java object for tag:yaml.org,2002:org.apache.cassandra.config.Config; exception=Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@250d593e; java.lang.reflect.InvocationTargetException
 in "<reader>", line 10, column 1:
    cluster_name: 'Test Cluster'
    ^

「aaa**:127.0.0.1」とでました。なんかKeyがなさそうです。
conf/cassandra.yamlを確認してみます。

0.7.4の時

seeds:
    #- 127.0.0.1

 
0.8betaの時

seed_provider:
    # Addresses of hosts that are deemed contact points.
    # Cassandra nodes use this list of hosts to find each other and learn
    # the topology of the ring.  You must change this if you are running
    # multiple nodes!
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          # seeds is actually a comma-delimited list of addresses.
          #- seeds: "127.0.0.1"

書き方が変わっており、初め「- 127.0.0.1」しか書いておりませんでした。(コピーアンドペースト
「- seeds: "127.0.0.1"」と書かなければいけなかったようです。*1

「- seeds: "127.0.0.1"」と書き直し、起動したところうまく動作させてことができました。
 

最後に

README.txtにしたがって、「family Users」に値を設定しようとしたらエラーがでました。

READMEより抜粋

  [default@unknown] create keyspace Keyspace1;
  ece86bde-dc55-11df-8240-e700f669bcfc
  [default@unknown] use Keyspace1;
  Authenticated to keyspace: Keyspace1
  [default@Keyspace1] create column family Users with comparator=UTF8Type and default_validation_class=UTF8Type and key_validation_class=UTF8Type;
  737c7a71-dc56-11df-8240-e700f669bcfc

  [default@KS1] set Users[jsmith][first] = 'John';
  Value inserted.
  [default@KS1] set Users[jsmith][last] = 'Smith';
  Value inserted.
  [default@KS1] set Users[jsmith][age] = long(42);
  Value inserted.
  [default@KS1] get Users[jsmith];
  => (column=last, value=Smith, timestamp=1287604215498000)
  => (column=first, value=John, timestamp=1287604214111000)
  => (column=age, value=42, timestamp=1287604216661000)
  Returned 3 results.

 
エラー内容

[default@Keyspace1] set Users[jsmith][first] = 'John';
org.apache.cassandra.db.marshal.MarshalException: cannot parse 'jsmith' as hex bytes

 
[jira]メーリングリストを眺めていると、「[Created] (CASSANDRA-2497) Issues with Update Column Family and adding a key_validation_class」
とあり、「I figured out that problem is in the CLI, will attach a patch tomorrow morning! 」とありました。

CLI: issue with keys being interpreted as hex and causing SET statement to fail

ただ、よくみるとパッチがあったので、パッチをあてて再度実行してみました。
(パッチの中身は、こちらを利用)

 cd src/java/org/apache/cassandra/cli/
 vi CASSANDRA-2497.patch
 patch < CASSANDRA-2497.patch

 
パッチ適用後、再度、「ant jar」で新しくjarを作りなおします。
cassandraのサービスを再起動後、cassandra-cliを試してみました。

 $ cassandra-cli
    Welcome to the Cassandra CLI.

    Type 'help;' or '?' for help.
    Type 'quit;' or 'exit;' to quit.

  [default@unknown] connect xx.xxx.xxx.xxx/9160;
  Connected to: "Test Cluster" on xx.xxx.xxx.xxx/9160
  [default@unknown]
  [default@unknown] use Keyspace1;
  Authenticated to keyspace: Keyspace1
  [default@Keyspace1] set Users[jsmith][first] = 'John';
  Value inserted.
  [default@Keyspace1] get Users[jsmith][first];
  => (column=first, value=John, timestamp=1303202057480000)
  [default@Keyspace1] exit;

無事、Column Familyに値を追加することができました。
 


*1:ダブルクォートで書き込まなくとも大丈夫なようです。