2012年1月26日木曜日

AndroidでDBの存在確認

AndroidでDBの存在確認の仕方は他にもあるけど、
データベースの保存場所がストレージであれば「/data/data/パッケージ名/databases/DB名」
に保存されるのでファイルの存在確認するのが手っ取り早い。
String DB_NAME = "test.db";

File file = new File(context.getDatabasePath(DB_NAME).getPath());
boolean dbExists = file.exists();

2012年1月11日水曜日

Androidでステータスバー(通知バー)を起動する

ステータスバーとか通知バーとかいろんな言い方あるけど、とにかくコレのこと↓

これを起動するのにちょいと手間がかかる。かかるといってもたいしたことはないけど。
まず、AndroidManifest.xmlに下記パーミッションを追加。
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />

あとはこんな感じのソースを書いて呼べばOK。
private void showNotifications() {
    try {
        Object service = getSystemService("statusbar");
        if (service != null) {
            Method expand = service.getClass().getMethod("expand");
            expand.invoke(service);
        }
    } catch (Exception e) {
    }
}

ちなみにHideなAPI使ってるのでいきなり使えなくなるかも?

2012年1月5日木曜日

twitter4jを使用してツイートするサンプルをHeroku上で動かす

RailsでHeroku上にTwitterサービスを作り始める場合「1時間でツイッターサービスを作ろう!」の記事が参考になる。
Railsもいいけど最近Androidでも活躍しているtwitter4jを使ってみたかったのでtwitter4jを使用して
ツイートをポストするWebアプリをHeroku上にデプロイしてみた。
twitter4jの作者である@yusukeさんのサンプルソースを流用するのでだいたい30分くらいで出来る。

事前準備

  • Gitインストール
  • Maven 3インストール
  • Herokuのアカウント作成
  • herokuコマンドインストール

Herokuアプリケーションの作成

$ heroku create --stack cedar
Creating blazing-mist-9962... done, stack is cedar
http://blazing-mist-9962.herokuapp.com/ | git@heroku.com:blazing-mist-9962.git

Twitterサービスの登録


https://dev.twitter.com/apps/newにアクセスして今回作成するサービスの情報を入力し登録する。
Callback URLはHerokuアプリケーションの作成時に表示されたURL + callback

Name(アプリケーション名):u1aryzの備忘録とか(任意)
Description(アプリケーションの説明):Herokuからtwitter4jを使用してツイートをポストするサンプル。(任意)
WebSite(ウェブサイトURL):http://u1aryz.blogspot.com/(任意)
Callback URL(コールバックURL):http://blazing-mist-9962.herokuapp.com/callback

登録し終わったらSettingsからApplication TypeをRead and Writeに変更。
Consumer keyとConsumer secretは後で使用するのでメモ。


twitter4jのサンプルソースをダウンロード


GitHubで公開されているtwitter4jのサンプルソースをダウンロードする。
yusuke / sign-in-with-twitter


Heroku(Jetty)用に修正&追加


pom.xml(修正)
<packaging>war</packaging>
↓変更
<packaging>jar</packaging>

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.4</version>
  <scope>provided</scope>
</dependency>
↓変更
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
</dependency>

pom.xml(追記)
dependenciesの子ノードに下記を追加
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-webapp</artifactId>
  <version>7.4.5.v20110725</version>
</dependency>
<dependency>
  <groupId>taglibs</groupId>
  <artifactId>standard</artifactId>
  <version>1.1.2</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>
<dependency>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jsp-2.1-glassfish</artifactId>
  <version>2.1.v20100127</version>
</dependency>

build,pluginsの子ノードに下記を追加
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>appassembler-maven-plugin</artifactId>
  <version>1.1.1</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>assemble</goal>
      </goals>
      <configuration>
        <assembleDirectory>target</assembleDirectory>
        <programs>
          <program>
            <mainClass>twitter4j.examples.signin.StartServer</mainClass>
            <name>webapp</name>
          </program>
        </programs>
      </configuration>
    </execution>
  </executions>
</plugin>

StartServer.java(新規)
package twitter4j.examples.signin;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;

public class StartServer {

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

        Server server = new Server(Integer.valueOf(System.getenv("PORT")));
        WebAppContext context = new WebAppContext("src/main/webapp", "/");
        context.setDescriptor("WEB-INF/web.xml");
        server.setHandler(context);

        server.start();
        server.join();
    }

}


twitter4j.properties(修正)
twitter4j.oauth.consumerKeyとtwitter4j.oauth.consumerSecretにそれぞれ上記で登録した内容を入れる。
入力したらファイル自体をプロジェクト直下に移動する。

Procfile(新規)
下記内容でプロジェクト直下に作成する。
web: sh target/bin/webapp

Herokuにデプロイ


デプロイといってもソースをプッシュするだけ。
$ cd プロジェクトディレクトリ
$ git init
$ git add .
$ git commit -m "Generate twitter app."
$ git remote add heroku git@heroku.com:blazing-mist-9962.git
$ git push heroku master

ツイートしてみる

$ heroku open

ログイン後、コールバックURLが呼ばれ下記のようなページが表示される。

公式Twitterで確認出来る通り、ツイート出来ていることがわかる。

2011年12月26日月曜日

Androidでファイルの入出力

汎用的なユーティリティー系の処理はその都度書いていては時間の無駄なので
ファイルの入出力の処理をコピペ出来るようにここに貼付けておく。
ちなみにファイルの入出力先は「/data/data/パッケージ名/files/」

FileUtils.java
package yourpackage;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;

public class FileUtils {

    /**
     * ファイルへ文字列を書き込み
     * @param context
     * @param str ファイル出力文字列
     * @param fileName ファイル名
     */
    public static void writeFile(Context context, String str, String fileName) {
        writeBinaryFile(context, str.getBytes(), fileName);
    }

    /**
     * ファイルへバイナリデータを書き込み
     * @param context
     * @param data バイトデータ
     * @param fileName ファイル名
     */
    public static void writeBinaryFile(Context context, byte[] data, String fileName) {
        OutputStream out = null;
        try {
            out = context.openFileOutput(fileName, Context.MODE_PRIVATE);
            out.write(data, 0, data.length);
        } catch (Exception e) {
            // 必要に応じて
//            throw e;
        } finally {
            try {
                if (out != null) out.close();
            } catch (Exception e) {
            }
        }
    }

    /**
     * ファイルから文字列を読み込む
     * @param context
     * @param fileName ファイル名
     * @return 文字列 ファイルがない場合はnull
     */
    public static String readFile(Context context, String fileName) {
        String str = null;
        byte[] data = readBinaryFile(context, fileName);
        if (data != null) {
            str = new String(data);
        }
        return str;
    }

    /**
     * ファイルからバイナリデータを読み込む
     * @param context
     * @param fileName
     * @return バイトデータ ファイルがない場合はnull
     */
    public static byte[] readBinaryFile(Context context, String fileName) {
        // ファイルの存在チェック
        if (!(new File(context.getFilesDir().getPath() + "/" + fileName).exists())) {
            return null;
        }

        int size;
        byte[] data = new byte[1024];
        InputStream in = null;
        ByteArrayOutputStream out = null;

        try {
            in = context.openFileInput(fileName);
            out = new ByteArrayOutputStream();
            while ((size = in.read(data)) != -1) {
                out.write(data, 0, size);
            }
            return out.toByteArray();
        } catch (Exception e) {
            // エラーの場合もnullを返すのでここでは何もしない
        } finally {
            try {
                if (in != null) in.close();
                if (out != null) out.close();
            } catch (Exception e) {
            }
        }

        return null;
    }
}

2011年12月16日金曜日

RubyでHerokuにデプロイするまでのメモ for Mac OS X (Snow Leopard)

Ruby使ったことないけどHerokuを使いたいがためにRailsを勉強することになった。
ちなみにHerokuは現在Node.js, Clojure, Java, Python, Scalaもサポートしているので
Railsじゃなくてもいいだろってツッコミがありそうだけど、もともとRubyのPaaSなので。
ということで環境構築からHerokuでデプロイするまでの流れをメモ。

事前準備

  • Xcodeインストール
  • MacPortsインストール
  • Gitインストール
  • Herokuのアカウント作成

MacPortsアップデート

$ export PATH=$PATH:/opt/local/bin/ # MacPortsのパスを通す
$ sudo port -d selfupdate
$ sudo port -d sync

RVM(Ruby Version Manager)インストール

$ bash < <(curl -sk https://rvm.beginrescueend.com/install/rvm)
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"' >> ~/.bash_profile
$ source .bash_profile
$ rvm --version

rvm 1.10.0 by Wayne E. Seguin (wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]

Rubyインストール


Herokuでのサポートされている1.9.2をインストール。
Macにもともと入っているRubyは1.8.7なので別途インストールする必要がある。
$ rvm pkg install readline
$ rvm install 1.9.2 --with-readline-dir=$HOME/.rvm/usr
$ rvm use 1.9.2 --default
$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin10.8.0]

必要なパッケージのインストール

$ gem install rails
$ gem install sqlite3
$ gem install heroku

プロジェクト作成

$ mkdir project
$ cd project
$ rails new herokuapp

ひな形を作成してマイグレーションを実行


どうせならHello World的なやつではなくscaffoldを使ってみる。
$ cd herokuapp
$ rails g scaffold Product title:string description:text image_url:string price:decimal
$ rake db:migrate

ローカルで実行


ローカルでアクセスしてみる。
$ rake routes
    products GET    /products(.:format)          {:action=>"index", :controller=>"products"}
             POST   /products(.:format)          {:action=>"create", :controller=>"products"}
 new_product GET    /products/new(.:format)      {:action=>"new", :controller=>"products"}
edit_product GET    /products/:id/edit(.:format) {:action=>"edit", :controller=>"products"}
     product GET    /products/:id(.:format)      {:action=>"show", :controller=>"products"}
             PUT    /products/:id(.:format)      {:action=>"update", :controller=>"products"}
             DELETE /products/:id(.:format)      {:action=>"destroy", :controller=>"products"}

$ rails s
ブラウザでhttp://localhost:3000/productsにアクセス。
正常にアクセス出来たら次へ。

Heroku用に修正&追加


Herokuは無料の範囲だとPostgreSQLを使うことになるのでGemfileの内容を下記のように書き換える。
gem 'sqlite3'
↓
gem 'pg'

必要なパッケージをインストールしてGitのローカルリポジトリへコミット。
$ sudo port install postgresql84
$ sudo ln -s /opt/local/bin/psql84 /usr/bin/psql
$ gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
$ bundle install
$ RAILS_ENV=production bundle exec rake assets:precompile
$ git init
$ git add .
$ git commit -m "Generate rails app."

Herokuへデプロイ


一番最初にHerokuアプリを作成する場合、emailとパスワードの入力を求められるので入力する。
$ heroku create
Enter your Heroku credentials.
Email: u1aryz.d@gmail.com
Password: 
Creating fierce-autumn-9435... done, stack is bamboo-mri-1.9.2
http://fierce-autumn-9435.heroku.com/ | git@heroku.com:fierce-autumn-9435.git
Git remote heroku added

$ git push heroku master
$ heroku rake db:migrate

デプロイされたWebアプリへアクセス

$ heroku open
これでブラウザが立ち上がるはずなので、urlにルートのパス(/products)を追加してアクセス。
最初はだいぶ手こずったけど次からは楽ちん。
便利な時代になったなー。

2011年12月14日水曜日

Redmine1.3.0をJettyで動作出来たときの各バージョン

RedmineをJetty上で動作させる手順は「RedmineをJettyで動かす覚え書き。」に詳しく書かれている。
しかし、gemとかRails、Rackなどその他いろいろなバージョンを合わせないと動作しないので
Jetty上でRedmine1.3.0を動作出来たときの各バージョンを記録しておく。

JRubyのバージョン

$ jruby -v
jruby 1.6.5 (ruby-1.8.7-p330) (2011-10-25 9dcd388) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_26) [linux-amd64-java]

gemのバージョン

$ jruby -S gem -v
1.3.7

その他のバージョン

$ jruby -S gem list

*** LOCAL GEMS ***

actionmailer (2.3.14)
actionpack (2.3.14)
activerecord (2.3.14)
activerecord-jdbc-adapter (1.2.1)
activerecord-jdbcsqlite3-adapter (1.2.1)
activeresource (2.3.14)
activesupport (2.3.14)
bouncy-castle-java (1.5.0146.1)
i18n (0.4.2)
jdbc-sqlite3 (3.7.2)
jruby-jars (1.6.5)
jruby-openssl (0.7.4)
jruby-rack (0.9.8)
rack (1.1.2)
rails (2.3.14)
rake (0.8.7)
rubygems-update (1.3.7)
rubyzip (0.9.5)
sources (0.0.1)
warbler (1.1.0)

ちなみにgem、Rails、warbler、jruby-rackを上記のバージョンを指定してインストールしたら動作出来た。
Rubyわからんと苦労するわー。

2011年12月12日月曜日

jetty8でBASIC認証

jettyでBASIC認証する必要があったので忘れずメモ。

jetty側の設定


まず認証レルムの設定ファイルを用意する。
用意すると言ってもデフォルトで$JETTY_HOME/etc/realm.propertiesが存在するのでこちらを利用する。
下記のフォーマットで記述する。
username: password[,rolename ...]
暗号化する場合は種類に応じてOBF:、MD5:、CRYPT:のプレフィックスを付与する。
暗号化する場合は下記のようにして生成する。
$ java -cp lib/jetty-xxx.jar:lib/jetty-util-xxx.jar org.mortbay.jetty.security.Password ユーザー名 パスワード
しかし、なぜか$JETTY_HOME/lib内にorg.mortbay.jetty.security.Passwordクラスが見つからなかったので
下記2つをダウンロードして生成する。
$ cd <workディレクトリ>
$ wget http://www.java2s.com/Code/JarDownload/jetty-core-6.1.14.jar.zip
$ wget http://www.java2s.com/Code/JarDownload/jetty-util-6.1.18.jar.zip
$ unzip jetty-core-6.1.14.jar.zip
$ unzip jetty-util-6.1.18.jar.zip
$ java -cp jetty-core-6.1.14.jar:jetty-util-6.1.18.jar org.mortbay.jetty.security.Password jetty password
password
OBF:1v2j1uum1xtv1zej1zer1xtn1uvk1v1v
MD5:5f4dcc3b5aa765d61d8327deb882cf99
CRYPT:je5/ATIGzeDQw

続いてjetty.xmlに認証レルムを使用する設定を追記する。
<Configure id="Server" class="org.eclipse.jetty.server.Server">
…
    <Call name="addBean">
      <Arg>
        <New class="org.eclipse.jetty.security.HashLoginService">
          <Set name="name">User Realm</Set>
          <Set name="config">
            <!-- 上記で用意した認証レルムの設定ファイルを指定 -->
            <SystemProperty name="jetty.home" default="."/>/etc/realm.properties
          </Set>
          <Set name="refreshInterval">0</Set>
        </New>
      </Arg>
    </Call>
…
</Configure>
Webアプリケーション毎に認証レルムを指定したい場合は下記のようにする。
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Set name="contextPath">/jetty</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/jetty</Set>
…
  <Get name="securityHandler">
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
            <Set name="name">User Realm</Set>
            <Set name="config">
              <SystemProperty name="jetty.home" default="."/>/etc/realm.properties
            </Set>
      </New>
    </Set>
  </Get>
…
</Configure>

Webアプリケーション側の設定


web.xmlにBASIC認証用の設定を追記する。
<web-app…
…
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Authentication of BASIC</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>User Realm</realm-name>
  </login-config>
  <security-role>
    <role-name>admin</role-name>
  </security-role>
…
</web-app>
ちなみに$JETTY_HOME/etc/webdefault.xmlに記述すれば一律で設定可能。