2014年12月31日水曜日

俳句調のツイートを検索して表示するWebアプリ作ってみた

俳句調のツイートを Twitter から検索して表示するWebアプリ作ってみた。

http://haiku-matcher.herokuapp.com/
https://github.com/ohbarye

テキストボックスに入力された値でツイートを取得して、その中から575調になっているものだけを表示する。
入力値がユーザ名なら、そのユーザのタイムラインから。ユーザ名でなければキーワード検索した結果からツイートを取得する。


言語/フレームワーク

  • Java8
  • Play Framework 2.2.6

□よかったこと
・やっぱりJava8で書くとコードが変わると思った。まだ知らない機能が多いので引き続き学びたい
・Play、噂通りで開発効率がかなり上がる
・特に立ち上げの速さ
・sbtによる依存性管理がストレスフリー
・Java EEから解放された感
 http://d.hatena.ne.jp/wyukawa/20140416/1397662264
・フルスタック感
・Hot Deploy
・scala templateの型安全性
…+まだやってないこといっぱいある

■困ったこと
・Play2.2系はJava8対応してなくて、sbtのバージョンあげたり結局諦めたエラーとかあった(2.3以降は対応済。よく調べずに2.2を選んだのは失敗)
・Playの更新頻度が高いので調べた情報が違うバージョンの情報…というのはよくあった

形態素解析

  • kuromoji

文章ぶち込むだけで解析結果を返してくれるライブラリ。全文検索エンジンの Solr とかでも使っているらしい。
Tweet から拾う単語は未知語(内蔵辞書に載ってない語)が多かった。今回は雑に処理したけど、そこらへん真面目にやろうとしたら自分で辞書用意する必要があるっぽくて震えた。

Twitter連携

  • twitter4j

直接 Twitter API を叩く必要ない。
ライブラリの問題じゃないけど、検索後によって401が返ってくるというよくわからないエラーでかなり悩んだ。時間を置いたりリトライしたら通るようになった。
いろいろググってたら Twitter から401エラーが返ってきて困った的な質問がめちゃ多くて世界中の悩み感があった。

プラットフォーム

  • heroku

初めて使ってみた。確かに爆速でデプロイできて便利っぽい。
環境・サーバ構築とかをほとんど考えなくてよくなったのでアプリ作る〜公開のハードルがまた下がった感がある。

けどまだ全然使いこなせてない。

git push heroku master した後の待ち時間が長いので休憩にしたりしてた。

フロントサイド

  • webjars
  • Bootstrap
  • LESS

フロントサイドの知識全然無いけど、この辺組み合わせるのがややモダンらしいので試してみた。
jqueryとか、クライアントサイドライブラリ揃えるのも確かに面倒なので webjars のこと知れてよかったという気持ちがある。

あまりよく知らないのでデザイン領域触れたくなかったけど、Bootstrap とか LESS とか試してみたら思ったより軽く書けたのでちょっと興味湧いた。けど深入りしたくない感じ。

その他感想

仕事で試す日が来ることは暫く無さそうで辛い(からい)。

2014年12月24日水曜日

[Play Framework] 設定ファイル(application.conf)から値を取得する

設定ファイル:application.conf に定義した値を取得する方法。意外と簡単で良かった。

とりあえず取得

key="value"
まず conf ファイルに定義する。
文字列にダブルクォーテーション付ける必要があるので注意。
Play.application()
       .configuration()
       .getString("key");    // "value" が取得できる

Configulationクラス

Configulation クラスには getString 以外にも getBoolean, getDouble など様々な型での値の取得が可能で便利だが、上記の書き方だとやたら長いのでラップしたメソッドを用意して使ってる。
 public static String getString(String key) {  
     return Play.application()
       .configuration()
       .getString(key);
 }

 public static boolean getBoolean(String key) {  
     return Play.application()
       .configuration()
       .getBoolean(key);
 }

2014年12月23日火曜日

[Play Framework] controllers 内でサブパッケージを作成する場合の注意点

Play Framework 始めた。

controllers 内にサブパッケージを作成して、その中のクラスおよびメソッドへのルーティングで一度失敗したのでメモ。

controller 直下のクラスにアクセスする

まず基本のおさらい。
パッケージ名:controllers
クラス名:MyClass
メソッド名:index
↑ココにアクセスしたい場合は以下のように routes とテンプレートファイルを編集する。
POST /index  controllers.MyClass.index()
@form(action = routes.MyClass.index) {
    <!-- 省略 -->
} 

controller 下のサブパッケージのクラスにアクセスする

本題はこのクラスのサブパッケージ内に作成する場合。
パッケージ名:controllers.sub
クラス名:MyClass
メソッド名:index
まず routes を修正する。
POST /index  controllers.sub.MyClass.index()
その後に scala.html 内のPOST先 action を修正。
サブパッケージ名をクラス名に付けてみる。
@form(action = routes.sub.MyClass.index) {
    <!-- 省略 -->
}
これでアクセスしてみると…
value sub is not a member of object controllers.routes
「"sub"なんてオブジェクトないよ」とのエラーメッセージ。
調べてみたところ完全修飾名で書けばOKとのこと。
There is a routes subpackage for each controller package. So the rightfully qualified name of your route is:@controllers.foo.routes.Home.index()
It's done this way to "see" the routes subpackage relatively from any
controllet package as "routes" 
[2.0] [Scala] routes for controller sub-packages - Google Groups -  
下記の通り修正したら無事通るようになった。
@form(action = controllers.sub.routes.MyClass.index) {
    <!-- 省略 -->
}

2014年12月22日月曜日

ローカルで作成したGitリポジトリを GitHub に push する

最近Git使い始めた。(仕事ではもっぱらSVN)
ローカル作業のバージョン管理だけやってたけどせっかくならGitHubも利用してみたい…ということでローカルに作成したリポジトリをGitHubに push する方法を調べた。

ほとんど↓に書いてある方法で出来たが、使ったことないコマンドあったのでメモしておく。
GitHubで、ローカルで作ったリポジトリから新規作成する - by shigemk2 - 

1. ローカルリポジトリ作成

今回はすでに完了していたけれども、まずローカルでリポジトリ作成〜コミットまで。
$ git init 
$ git add -A
$ git commit -m "optional message"

2. GitHubでリポジトリ作成

GitHubで "new repository" 。

3. リモートリポジトリを追加する

下記コマンドでリモートリポジトリ追加。
$ git remote add origin "https://github.com/<user name>/<repository name>"

4. ようやく push

$ git fetch
$ git merge origin/master
$ git push -u origin master

"-u branch master" は紐付けのために初回のみ必要とのこと。

git fetch ってとは。
git merge はなんとなくわかるがどんな挙動なんだ…というのは下記で。
fetch【リモートリポジトリ】 | サルでもわかるGit入門 〜バージョン管理を使いこなそう〜 | どこでもプロジェクト管理バックログ - 
git fetchの理解からgit mergeとpullの役割 - Qiita - 


結果、GitHubに push できた。
https://github.com/ohbarye/PlayPractice

【余談】

途中、リモートリポジトリ名を間違えた。再度 git remote add しようとしたら、エラーが出た。その時の対応は下記。
【githubエラー】fatal: remote origin already exists.の対処 - iwaheiもといロックソルジャーのweb(メモ||日記) - 

APPLE MacBook Pro Retinaディスプレイ 2200/15.4 MGXA2J/A 買ったら最高だった

 Mac mini 売った

MacBook Pro 買ったと言いつつ、まず Mac mini 打った話。

長らく Windows を使いつつも Mac に対する漠然とした憧れがあって今年6月に Mac mini を買った。主に開発と音楽編集とかやろうと思ってた。

けど周辺機器を全然揃えてなかったのでほとんど使えなかった。
  • ディスプレイがないのでテレビにHDMI接続してたけど、解像度を合わせるのも面倒でそのまま見てたら目が疲れた
  • Mac 用のキーボードがないので Windows 用のキーボードを使っていたけど、キー配置が訳わからなくなって入力に疲れた
  • トラックパッドがないので操作時にはマウスを使うことになってこれも疲れた
いろいろ揃えればなんとかなるってわかってももはや面倒くさくて熱が冷めていたので、テレビで映画観る時には Mac mini から再生する…ぐらいにしか使ってなかった。

Mac の利点をまったく活かせていないどころかPCとして全然機能しておらずインテリアになっていたので ¥44,000 で売却した。

全部自分のせいっちゃせいなんだけど、こういうのをいちいち調べて揃えるのも面倒な人はけっこういると思う。Mac mini、低価格で Mac に触れられるのは良いと思うけど、そいう意味で自分には向いてなかった。ケチって失敗したパターンだと思う。

MacBook 買った

なので最初からオールインワンになってる MacBook Pro 買うことにした。この時、もともと使ってた Lenovo のノートが限界近かった&ので選択肢はノート一択。

先に書いた通りめんどうくさがりで機能を全部集約したく、もう「コレ買っておけばもういいだろ」的なやつをケチらずに買おうとしてたので 15.4 インチの 16GB, SSD 256GB の MacBook Pro Retina : MGXA2J/A にした。

購入価格 ¥180,000 ぐらいだったので mini の売却資金差し引いてもややキツかったけど、買ってよかった。この買い物は全肯定できる。

ファーストインプレッション

いろんな人がいろんな利点を褒めてるので今更感しかないけれども、
第一印象はこんな感じ。

  • Retina ディスプレイ、フォントが良い。目に優しいし、ブラウジングもコーディングも長時間集中してても疲れにくくなった。たしかにこの後に Windows 触ったら文字がギザギザして見えた。
  • トラックパッドのおかげでマウス捨てた。iPhone みたいに操作できてストレスがない。
  • 見た目がかっこいい。出社するときに家に置いて行きたくない。
  • ボディ、トラックパッドの質感が良い。すべすべしてるので指がひっかかったりしない。
  • いちいちヌルヌル動くのが良い。トラックパッドでスクロールした時に指を離しても吹っ飛んでいったり、最下まで行ったあとにバウンドするように戻っていったりする。なんでこんな無駄っぽい動きに感動するんだろう、って思ったけど、これ本能っぽい。自然界の慣性を模倣した動きを前にすると優しい気持ちになれる気がする。感性学とかで説明してほしい。
  • SSDだと起動がめちゃ早い。Windows、基本的に再起動したくなかった。パッチ適用〜再起動とかいう最悪の定期作業で大体5分ぐらいかかっててその間は休憩するか〜とか言って携帯で twitter 見てた。二度とやりたくない。

MacBook に触ってるうちに「PCに対して自分が今までどれだけ我慢してきたか」に気づいた。これまで意識もしてなかったことが、実は積もり積もってけっこうなストレスになっていたっぽい。書いてて熟年離婚感がある。

高価な買い物して魔法にかかっている感も否めないけれども、PCは毎日触るので毎日満足感に浸れる。なので今年一番の満足してる。
とにかく家でPCに向かうのが以前より遥かに好きになったので良かった。

ただ会社では支給される Windows7 しか使えないのでいろいろ辛い。

2014年12月2日火曜日

選挙での「白票」を「社会を変える力がある」と主張していた団体について、福沢諭吉的な観点から思ったこと

選挙での「白票」を「社会を変える力がある」とミスリードする謎の集団「日本未来ネットワーク」のサイトが突如出現 | BUZZAP!(バザップ!) - http://goo.gl/Fx820u

こういうのに飛びつく人間が周囲にいたので、なんだかなぁ…と思っていた。
思っているだけだったので、諭吉の言葉などを使って表現してみた。

政治に関心の無い人間の一例として、"コンディショナル・グッド-条件付き善-"、つまり絶対的な価値判断でなくて状況によって制約された善悪というものを理解していない。かんたんに言えば相対的な価値判断ができない。

価値判断ではたびたび、ベストな選択ではなくベターな選択を強いられる。また、政治的な判断に代表されるように、「悪さ加減」が価値判断の根拠となることもある。これは状況認識の話だが、悪いものばかり並べてみるのは精神的に苦痛、という精神衛生にも関わってくる。こうした状況に手っ取り早い結論を求めるようなひ弱な精神は耐えられない。だから判断を投げ出す。

投げ出すだけならまだ良いのだが、投げ出す行為にあたかも主体性があるかのように振る舞うタイプの人間もいる。これは独立ではなく単なる機会主義であり、やはり"惑溺"の一種なのである。

この"惑溺"こそ福沢が激しく批判した状況認識・判断の誤りであるからこそ、絶対にブッ飛ばす必要があるのでムカついてたとわかった。

2014年10月25日土曜日

『プロとしてのデータモデリング入門』書評

担当案件でDB設計やることになった。
ERDなどの設計書類は読んでいたけれども、ゼロからどうやって設計するのかをきちんと理解しないとな~と思い、評判良かった『プロとしてのデータモデリング入門』を読んだ。

とにかく実践的で良かった。
データモデリング、データベース設計の入門におすすめ。

説明が丁寧

入門と付くだけあって平易な表現で基礎的な説明から入っていき、説明に冗長な印象もあったが入門ということで特に気にはならなかった。何より、なぜその要素が大切なのか?現場ではどのように捉えられているのか?をしっかり解説してくれていので丁寧さと映った。

特に、モデリングにて最重要となるER図の書き方には多くのページを割いていて、これ一冊でER図は書けるようになる。

実用的なテクニックが多い

アプリケーションとの連携や実運用をきちんと見据えた方法論を提示してくれていて、これがまた良い。現場ですぐに使える。
  • 業務要件が固まっている場合のトップダウン・アプローチ、画面イメージから入る場合のボトムアップ・アプローチ
  • 性能要件を満たすための導出項目の設計や非正規化
  • データの更新・参照頻度を意識した索引の設計  etc.

スーパータイプ/サブタイプ使える

個人的に最も役に立ったのがスーパータイプとサブタイプの分割。
オブジェクト指向的な考え方をデータ設計でもできるのか~と眼から鱗。

これを実際に現場で試してみて、現実で単一/複数のエンティティでも、実態を整理すると分割/統合できることがわかり、そうして整理することでより説明に適したERDが書けるようになった。

また、概念的にスーパー/サブタイプに分かれていても、論理設計(テーブル設計)では必ずしも分割する必要は無い、というのも実践的なポイント。これを取り入れることで、概念的なERと実際のテーブルの関連それぞれを多層的に捉えられるようになった。


当然ながらこれ一冊でDB設計が完璧になることはない。
処理(プロセス)との関連を含めて最適なアーキテクチャを探る方法や、データベース製品の機能を利用して実現できるプラクティスについて多くは触れていない。そこを考える以前の話なので。

データモデリングの基礎の理解が曖昧で、もう少し正確に理解したい…という人にはおすすめ。
DB設計面白い。

2014年10月22日水曜日

[DB設計] リレーショナルデータベースでは履歴の管理をすべきでない?

リレーショナルデータベースで履歴の管理は難しい。


いまDB設計を担当している案件で、業務用件として履歴管理が現れた。
「データの更新の度に更新前後のデータを保持し、過去のある時点のデータを再現したい」という。

どう実装するか。。

追加のみ行うよう設計する

はじめに考えたのはテーブルAにはレコードの追加のみ行う、という方法。
しかし…下記の理由により断念。
  1. テーブルAのオカレンスは頻繁に更新され、レコード数が大変なことになる。オンライン処理の為、厳しい。
  2. また、今回はテーブルAだけでなく、テーブルAとリレーションを持つ他の幾つかのテーブルの履歴も持たなければならない。つまり、テーブルAを更新する為に他の複数のテーブルにINSERTを行わなければならなくなってしまう。これをアプリケーション実装者に強いるのはリスク。

本体と履歴の情報を分ける

テーブルAとは別にテーブルA履歴を用意する方法。履歴テーブルにはテーブルAの主キーとリビジョンなどを持たせる。最新のデータを取得するにはテーブルAを見るだけで良いので問題1.は解決。

テーブルAの更新と同時にテーブルA履歴にINSERT。これも問題2.を孕んでいるが、テーブルUPDATE,INSERT,DELETE時に履歴系テーブルにINSERTするトリガーを作成することでやや改善する。データの追加・更新・削除は履歴を意識せず、本体に行えば良いのでアプリ実装負担にはならないはず。


ひとまずこんな感じで設計したが、未だ残る一番の懸念は履歴に対する検索処理。とにかく重そう。
集計表としてマテリアライズド・ビューの作成も検討しているが、検索条件の柔軟な変更に対応できるだろうか?また、対応コストは高くつかないだろうか?
もう少し、考えてみたい。

履歴とは


ちなみに【DOAコラム】-更新と履歴によると、履歴には3種類があるという。(詳細はリンク先参照)
1.単純に行為・出来事の事実を記録する履歴
2.元の行為・出来事が変更されるので、変更前の状態を記録する履歴
3.継続的な発生を前提にして、行為・出来事の事実を記録する履歴
今回の要件では2.に当たる。このうち1.と3.の実態はイベント(行為/出来事)の集積であって、イベントテーブルを作ってそこにレコードを追加していけばよいとのこと。

【参考】


2014年10月9日木曜日

[html] name属性を定義していないinputタグのformデータは送信されない

当たり前のことだけどこれの不理解に起因するバグがあって時間とられたのが悔しいのでメモ。
まぁ、テンプレートエンジン使ってると見落としがちなのかもしれないが…。

[JavaScript] wait~リトライを行う処理

クライアントサイドJavaScriptでwait処理に相当するものが必要になったので調べてみた。

そもそもJavaScriptにはwait / sleep に相当する関数が無いみたいだが、
遅延処理を実現する setInterval() / clearInterval() の2つのメソッドにて同様の関数を実装できると判明。

今回は純粋なwait処理だけでなく、非同期に行われる処理との同期をとるためのチェックも行える必要があったのでこんな関数を書いた。

/* 
 * 条件を満たすか、指定回数だけリトライするまで待つ
 * ループ処理としても使える
 * [引数]    test        :終了条件を満たすかどうか判断する関数
 *             callback    :終了条件を満たした後に呼び出す関数
 *             time        :ポーリングタイム(ms)
 *             retry        :リトライ回数
 */
function wait(test,callback,time,retry) {
    // リトライ指定が無い場合はデフォルト回数を設定
    if(retry === undefined) { retry = 3; }
    
    var count = 0;
    
    // wait条件を満たすまで繰り返す処理
    var process = function() {
                        count++;
                        if(test() || (count > max)) {
                            clearInterval(timer);
                            callback();
                        }
                    };
    var timer = setInterval(process(),time);
}


参考にしたサイトでも指摘されていたが、時刻の取得→比較を繰り返すのはブラウザが固まってしまうアンチパターンなのでNG。

普段はJavaばかり書いてるので、JavaScriptでクロージャを意識したコードを書くの楽しい。

【参考】
【JavaScript】処理の実行タイミングを遅らせる方法 | Web制作会社スタイル
遅延実行 | JavaScript プログラミング解説
javascript で wait処理 - 新みのる日記

2014年9月19日金曜日

[カメラ] 逆光を利用して写真を撮る

友達の記事:井山の写真の解説 | 写真をちょっといい感じにする方法集を読んで感化されたので谷中近辺を散策しつつ、実践してみた。

とりあえず一枚…
それらしき感じのが撮れて良かったが、この花の名前がわからないので誰かに同定してほしい次第。





Bloggerでデザインを変更したらHTMLテンプレートが初期化された

タイトルそのままだが、Bloggerでデザインを変更したらHTMLテンプレートが初期化された。

デザイン変更直後にSyntaxHighlighterが効かなくなってるな~と思っていたら、jsファイルを読み込んで無かったのでもしやと思い確認したところ、やっぱり初期化されていた。

↓をHTMLに追記して、OK。


<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = &#39;http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf&#39;;
SyntaxHighlighter.all();
</script>

2014年9月6日土曜日

[Java] JDKコマンドを使う時は対象のVMとバージョンを合わせる

でないと VMVersionMismatchException という非常に明確なExceptionが飛ぶ。

$ jstack -F 5268
Attaching to process ID 5268, please wait...
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at sun.tools.jstack.JStack.runJStackTool(JStack.java:136)
        at sun.tools.jstack.JStack.main(JStack.java:102)
Caused by: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 23.5-b02. Target VM is 23.1-b03
        at sun.jvm.hotspot.runtime.VM.checkVMVersion(VM.java:234)
        at sun.jvm.hotspot.runtime.VM.(VM.java:297)
        at sun.jvm.hotspot.runtime.VM.initialize(VM.java:367)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.setupVM(BugSpotAgent.java:598)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.go(BugSpotAgent.java:493)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.attach(BugSpotAgent.java:331)
        at sun.jvm.hotspot.tools.Tool.start(Tool.java:163)
        at sun.jvm.hotspot.tools.JStack.main(JStack.java:86)
        ... 6 more


表示されるバージョンはJVM(上の例だとHotSpot)のバージョン。
JavaSEとかに比べるとあまり馴染みが無い。
Supported versions are 23.5-b02. Target VM is 23.1-b03

【参考】

7杯目のおかわりコーヒーはイルカの夢を見るか? - Programming Studio -

2014年9月5日金曜日

[SAStruts] SAStrutsのActionではgetから始まるメソッド名を付けてはいけない

ActionクラスにgetHogeという名前のメソッドを追加したところ、変更箇所以外の挙動がおかしくなった。

SAStrutsの落とし穴 - じゃばらの手記 -によると…
SAStrutsJSPレンダリングするとき、ActionFormとActionのプロパティとpublicフィールドの値をMapに詰め込みます。こうすることでpublicフィールドをJavaBeansのプロパティのような感覚で扱うことが出来るわけです。
ハマった。。

【環境】

sa-struts-1.0.4-sp9

2014年9月4日木曜日

[Java] jpsコマンドでTomcatのプロセスが表示されない


jps ツールは、ターゲットシステム上で計測された HotSpot Java 仮想マシン (JVM) を一覧表示します。このツールで表示できるレポート情報は、アクセス権を持った JVM に関するものに限定されます。(jps - Java 仮想マシンプロセスステータスツール -
というから、
起動中のTomcatのPIDを知りたくてjpsコマンドを実行したら。
$ jps
8960 Jps
jpsコマンドのプロセスしか結果に表示されない。 ググったところ、jpsコマンドでTomcatのプロセスが表示されない場合の対処方法がすぐ見つかった。

jpsコマンドはjavaアプリケーションが出力するtempファイルからプロセス情報を拾っているとのこと。

Windowsだと下記ディレクトリにPIDがファイル名のファイルが生成されていた。

C:\Users\[ログオンユーザ名]\AppData\Local\Temp\hsperfdata_[ログオンユーザ名]


で、Tomcatはと言うと、システムプロパティ:java.io.tmpdirで指定したディレクトリにPIDファイルを出力する。デフォルトだと $CATALINA_HOME\temp になる気がする…、未確認。

JVMの起動オプションで出力先をjpsの確認先にしてやり、Tomcatを再起動すると…
-Djava.io.tmpdir=C:\Users\[ログオンユーザ名]\AppData\Local\Temp\hsperfdata_[ログオンユーザ名]

jpsコマンドでTomcatのPIDが表示されることを確認。

$ jps
13212 Bootstrap
8960 Jps

Tomcat以外にも独自のファイルを作成するjavaアプリケーションはありそう。

【環境】

JDK 6.0.45
Tomcat 6.0系(マイナーバージョン未確認)

2014年9月1日月曜日

[カメラ] 女の子を可愛く撮る方法

カメラに詳しく数々の女の子を可愛く撮ってきた友達から女の子を可愛く撮る4つのコツを教わった!!


1.出来る限り"絞る"

F値を出来る限り下げて、焦点が被写体だけに合うようにする。
これだけで「この写真の主役はこいつだ!!」って感じになる。

ただし焦点距離を狭めすぎると、眼にはピントが合うけど鼻には合っていない…みたいな現象が起きるので絞りは「出来る限り」。

2.露出補正を高める

出来上がりの明るさ(露出補正)を高める。
+0.3~1.0ぐらい。美白効果と写真の仕上がりがふんわりした感じになる。

ただし上げまくるとプリクラみたいな感じになって怖い。
逆に下げていくとくっきりして強そうな感じになるっぽい。

3.被写体の目線より上から撮る

写真に限らず対人時の視線の高低は印象を変えるので、上から撮ると「守ってあげたい…」感が出るらしい。
逆に下から撮ると「強そう…偉そう…」感が出るらしい。

4.眼に光が入り込むようにする


眼のキラキラ感、それが若さらしい。


現在試行中!!!

2014年7月24日木曜日

[MySQL] 外部から接続するのに失敗しまくった(ファイアウォール、my.cnf、権限)

LinuxにインストールしたMySQLに外部から接続するのに何度も失敗して結構時間食った。

ファイアウォールでやらかす

まず最初のエラー。下記コマンドを試みる。
C:\Users\>mysql -u <MySQLのユーザ> -h '<DBサーバIP>' -p
Enter password: *********
すると、
ERROR 2003 (HY000): Can't connect to MySQL server on '<クライアントIP>' (10060)
"Can't connect to MySQL server" でググった結果、DBサーバのファイアウォールの設定では?とのこと。
iptables -L
して設定状況を確認する。
INPUTチェインでREJECTしているルールがあったので削除。
(本来はダメだろうけど、とりあえず問題を切り分ける為に実施)

my.cnf でやらかす

再度接続を試みると、
ERROR 1042 (HY000): Can't get hostname for your address
またググる。
MySQLの設定ファイル my.cnf に下記を追加すれば良いらしい。
skip-name-resolve
↓の通り追加した。
[mysqld]
(略)
skip-name-resolve
(略)

権限でやらかす

再度接続を試みると、
ERROR 1130 (HY000): Host '<クライアントIP>' is not allowed to connect to this MySQL server
またググる。
ログインを試みているユーザに、クライアントPCからアクセスする権限を付与しないといけないらしい。
GRANT ALL PRIVILEGES ON *.* TO <MySQLユーザ>@'<クライアントIP>' IDENTIFIED BY '<パスワード>' WITH GRANT OPTION;
実際はデータベースやテーブルをちゃんと指定する必要あり。。 これでようやく…
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.5.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

【参考】

MySQLで外部から接続するときにチェックする項目 - yummy-yummy
MySQL を外部接続できるようにする - 怠惰な日々
Linuxコマンド集 - 【iptables】パケットフィルタリングを設定する:ITpro

2014年7月13日日曜日

[S2Chronos] リクエストをトリガーにTaskを非同期実行

本来の使い方に即しているかわからないけど、S2Chronosで非同期処理が簡単に実現できる。

前回書いた記事の通りに設定を行った後、リクエストをトリガーにTaskを非同期実行するプログラムを書いた。
package org.seasar.example.action;

import javax.annotation.Resource;

import org.seasar.chronos.core.Scheduler;
import org.seasar.example.task.SampleTask;
import org.seasar.framework.log.Logger;
import org.seasar.struts.annotation.Execute;

public class IndexAction {

    private static final Logger logger = Logger.getLogger(IndexAction.class);

    @Resource
    private Scheduler scheduler;

    @Execute(validator = false)
    public String index() throws InterruptedException {

         // タスク登録
         // 登録後、Chronosがプールしている別スレッドで自動実行
         scheduler.addTask(SampleTask.class);

        // 実行状況を確認するログ出力
        for (int i=0;i<10;i++) {
            logger.info("アクションの処理実行中 " + i);
            Thread.sleep(1000);
        }
        return "index.jsp";
    }

}
package org.seasar.example.task;

import org.seasar.chronos.core.annotation.task.Task;
import org.seasar.chronos.core.annotation.task.method.NextTask;
import org.seasar.chronos.core.annotation.trigger.NonDelayTrigger;
import org.seasar.framework.log.Logger;

@Task(autoSchedule=false)
@NonDelayTrigger
public class SampleTask {

    @NextTask("test")
    public static void doExecute() throws InterruptedException {

        // 実行状況を確認するログ出力
        for (int i=0;i<10;i++) {
            logger.info("タスクの実行中 " + i);
            Thread.sleep(800);
        }
    }

    private static final Logger logger = Logger.getLogger(SampleTask.class);

    public void initialize() {
        logger.info("[initialize]");
    }

    public void start() {
        logger.info("[start]");
    }

    public void finish() {
        logger.info("[finish]");
    }

    public void destroy() {
        logger.info("[destroy]");
    }
}
ブラウザからリクエストを送信した結果が下記。 非同期処理が実現されている。
DEBUG 2014-07-13 21:40:30,588 [http-bio-8080-exec-8] BEGIN org.seasar.example.action.IndexAction#index()
DEBUG 2014-07-13 21:40:30,599 [http-bio-8080-exec-8] トランザクションを開始しました。tx=[FormatId=4360, GlobalId=1405255230598/0, BranchId=]
DEBUG 2014-07-13 21:40:30,599 [http-bio-8080-exec-8] BEGIN org.seasar.chronos.core.impl.SchedulerImpl#addTask(class org.seasar.example.task.SampleTask)
DEBUG 2014-07-13 21:40:30,604 [http-bio-8080-exec-8] END org.seasar.chronos.core.impl.SchedulerImpl#addTask(class org.seasar.example.task.SampleTask) : true
INFO  2014-07-13 21:40:30,604 [http-bio-8080-exec-8] アクションの処理実行中 0
INFO  2014-07-13 21:40:31,604 [http-bio-8080-exec-8] アクションの処理実行中 1
INFO  2014-07-13 21:40:32,604 [http-bio-8080-exec-8] アクションの処理実行中 2
INFO  2014-07-13 21:40:33,605 [http-bio-8080-exec-8] アクションの処理実行中 3
DEBUG 2014-07-13 21:40:33,875 [chronos-pool-3-thread-1] BEGIN org.seasar.example.task.SampleTask#initialize()
INFO  2014-07-13 21:40:33,876 [chronos-pool-3-thread-1] [initialize]
DEBUG 2014-07-13 21:40:33,876 [chronos-pool-3-thread-1] END org.seasar.example.task.SampleTask#initialize() : null
INFO  2014-07-13 21:40:34,605 [http-bio-8080-exec-8] アクションの処理実行中 4
INFO  2014-07-13 21:40:35,605 [http-bio-8080-exec-8] アクションの処理実行中 5
DEBUG 2014-07-13 21:40:35,879 [chronos-pool-1-daemonthread-1] タスク (org.seasar.example.task.SampleTask) を 開始します.
DEBUG 2014-07-13 21:40:35,881 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 開始しました.
INFO  2014-07-13 21:40:35,882 [chronos-pool-3-thread-1] [start]
INFO  2014-07-13 21:40:35,886 [chronos-pool-3-thread-1] タスクの実行中 0
INFO  2014-07-13 21:40:36,605 [http-bio-8080-exec-8] アクションの処理実行中 6
INFO  2014-07-13 21:40:36,686 [chronos-pool-3-thread-1] タスクの実行中 1
INFO  2014-07-13 21:40:37,486 [chronos-pool-3-thread-1] タスクの実行中 2
INFO  2014-07-13 21:40:37,605 [http-bio-8080-exec-8] アクションの処理実行中 7
INFO  2014-07-13 21:40:38,286 [chronos-pool-3-thread-1] タスクの実行中 3
INFO  2014-07-13 21:40:38,605 [http-bio-8080-exec-8] アクションの処理実行中 8
INFO  2014-07-13 21:40:39,086 [chronos-pool-3-thread-1] タスクの実行中 4
INFO  2014-07-13 21:40:39,605 [http-bio-8080-exec-8] アクションの処理実行中 9
INFO  2014-07-13 21:40:39,886 [chronos-pool-3-thread-1] タスクの実行中 5
DEBUG 2014-07-13 21:40:40,609 [http-bio-8080-exec-8] トランザクションをコミットしました。tx=[FormatId=4360, GlobalId=1405255230598/0, BranchId=]
DEBUG 2014-07-13 21:40:40,609 [http-bio-8080-exec-8] END org.seasar.example.action.IndexAction#index() : index.jsp
DEBUG 2014-07-13 21:40:40,630 [http-bio-8080-exec-8] 

** after *****************************************: /index.do
  Response class=org.apache.catalina.connector.ResponseFacade, instance=org.apache.catalina.connector.ResponseFacade@413803ba
  [request]indexAction=org.seasar.example.action.IndexAction$$EnhancedByS2AOP$$60223be4@60c0a150
  [request]indexActionForm=org.seasar.struts.action.ActionFormWrapper@447cc9c9
  [request]javax.servlet.forward.context_path=/s2sample
  [request]javax.servlet.forward.request_uri=/s2sample/
  [request]javax.servlet.forward.servlet_path=/
  [request]org.apache.struts.action.MESSAGE=org.seasar.struts.util.S2PropertyMessageResources@5ca3ce3f
  [request]org.apache.struts.action.MODULE=org.seasar.struts.config.S2ModuleConfig@639b99d
  [request]org.apache.struts.action.mapping.instance=ActionConfig[path=/index,name=indexActionForm,scope=request,validate=false,cancellable=false
  [request]org.seasar.struts.util.S2ExecuteConfigUtil=org.seasar.struts.config.S2ExecuteConfig@37c8f59c
  [cookie]JSESSIONID=B594B4C31C8CDCC115905A8A57A739AA
  [cookie]JSESSIONID=560C273D113E86C2FED64320DEADF6AB
  [session]org.apache.struts.action.LOCALE=ja

INFO  2014-07-13 21:40:40,702 [chronos-pool-3-thread-1] タスクの実行中 6
INFO  2014-07-13 21:40:41,502 [chronos-pool-3-thread-1] タスクの実行中 7
INFO  2014-07-13 21:40:42,302 [chronos-pool-3-thread-1] タスクの実行中 8
INFO  2014-07-13 21:40:43,102 [chronos-pool-3-thread-1] タスクの実行中 9
INFO  2014-07-13 21:40:43,903 [chronos-pool-3-thread-1] [finish]
DEBUG 2014-07-13 21:40:43,904 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 終了します.
DEBUG 2014-07-13 21:40:43,905 [chronos-pool-1-daemonthread-2] タスク (org.seasar.example.task.SampleTask) を 終了しました.
DEBUG 2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] BEGIN org.seasar.example.task.SampleTask#destroy()
INFO  2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] [destroy]
DEBUG 2014-07-13 21:40:47,885 [chronos-pool-3-thread-1] END org.seasar.example.task.SampleTask#destroy() : null
もちろん自分でスレッド作っても同じだけど、こっちのほうがコード少なくてすむ。
また、あまり多くないかもしれないが、契機が時間でなくリクエストとなる(API的な)バッチ処理や、画面からバッチの実行を制御するような場合にはこんな感じで実現すると良さそう。

【環境】

Java SE7
Seasar2.4.45
S2Chronos1.0.0

2014年7月11日金曜日

[VBS][JavaScript][IE操作] 信頼済みゾーンのサイトでIEオブジェクトが動かない

社内システムから定期的に情報を取得してメールを送信するバッチをJavaScriptで実装していると、
"そのインターフェイスは認識されません。"
やら
"エラーを特定できません。"
とのエラーが。 エラー発生箇所を見ると↓の4行目で落ちていた。
var ie = WScript.CreateObject("InternetExplorer.Application");

// IE読み込み待ち
while(ie.Busy or ie.ReadyState <> 4) {
}
エラーメッセージでググって出てきたheipooh's 日記 を見てみると
ゾーンの設定変更で解消したとのことなので、試してみたところうまくいった。

【環境】
Internet Explorer 8
※古い。。

2014年7月8日火曜日

[SAStruts] RequestProcessor 内で Action やMethod のインスタンスを取得する

Seasar2のS2RequestProcessorを拡張しての共通処理に挑戦中。

やりたいことは殆ど『Seasar2 徹底入門』の「6.5 認証処理を実装する」の通りだけども、自前の処理を書くと途端に戸惑う。
特に、呼び出されるMethodやActionの取得方法がわからなくて困った。
調べる前にS2RequestProcessorのソースを見てたら類似の処理があったので、おそらくこれかな~。
// Actionの取得
S2ActionMapping s2mapping = S2ActionMappingUtil.getActionMapping();
Object action = s2mapping.getAction();
やりたい共通処理は認証で、自前のAbstractActionを継承したActionにのみ行いたい処理を今回のRequestProcessorに書くつもり。

認証を行う対象はアノテーションでマーキングすべきかと思ったけど、AbstractActionに認証用のDtoを定義している。
その為、↑で取得したActionのプロパティを見て対象を判定することにする。
// Methodの取得
S2ExecuteConfig executeConfig = S2ExecuteConfigUtil.getExecuteConfig();
Method method = executeConfig.getMethod();
なんとなく、org.seasar.struts.utilパッケージのユーティリティが鍵っぽい。

SAどころかStrutsの中身もちゃんと見たことないので、この機会にもう少し学んでみよう。

2014年7月4日金曜日

[Seasar2] S2Chronos1.0.0 のセットアップが公式通りだとうまくいかない

"Seasar2に対応したJavaオブジェクトスケジューリングフレームワーク"、S2Chronosの有用性検証を依頼されたのでセットアップ。

公式を見ながら行ったのだが、diconファイルの読み込みあたりでClassNotFoundExceptionなんかが頻発。。いくつかのblogを参考にしてみると公式に記載の無い設定が必要だったりした。

以下、インストールに要した全作業。

1. S2Choronosのjarファイルを↓からダウンロード。WEB-INF/lib に配置し、ビルドパスに加える。
 http://s2chronos.sandbox.seasar.org/ja/download.html

 ソースは下記から。
 http://maven.seasar.org/maven2/org/seasar/chronos/s2chronos-core/1.0.0/
 http://maven.seasar.org/maven2/org/seasar/chronos/s2chronos-extension/1.0.0/


2.chronosCustomize.dicon を作成し、 src/main/resource に配置する。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components>
    <component name="schedulerConfiguration" class="org.seasar.chronos.core.SchedulerConfiguration">
        <property name="hotdeployDisable">true</property>
        <property name="daemon">true</property>
        <property name="autoFinish">false</property>
        <property name="autoFinishTimeLimit">5000L</property>
        <property name="taskScanIntervalTime">2000L</property>
        <property name="threadPoolType">@org.seasar.chronos.core.ThreadPoolType@CACHED</property>
    </component>
</components>
※ chronosCustomizer.dicon ではないので要注意。
※ パッケージ名のorg.seasar.chronos.coreが公式だと org.seasar.chronos.core.model になっている。1.0.0ではmodelというパッケージは存在しないので修正する。

3. creator.dicon の<components>タグ中に下記を追記する。
<component class="org.seasar.chronos.core.creator.TaskCreator"/>
<component class="org.seasar.chronos.core.creator.TriggerCreator"/>
4. customizer.dicon の<components>タグ中に下記を追記する。
 <component name="taskSupportAspectCustomizer" class="org.seasar.framework.container.customizer.AspectCustomizer">
   <initMethod name="addInterceptorName">
    <arg>"aop.traceInterceptor"</arg>
   </initMethod>
   <property name="pointcut">"do.*, initialize, destroy"</property>
 </component>
 <component name="taskCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
  <initMethod name="addCustomizer">
   <arg>taskSupportAspectCustomizer</arg>
  </initMethod>
 </component>
 <component name="triggerSupportAspectCustomizer" class="org.seasar.framework.container.customizer.AspectCustomizer">
  <initMethod name="addInterceptorName">
   <arg>"aop.traceInterceptor"</arg>
  </initMethod>
  <property name="pointcut">".*"</property>
 </component>
 <component name="triggerCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain">
  <initMethod name="addCustomizer">
   <arg>triggerSupportAspectCustomizer</arg>
  </initMethod>
 </component>
5. app.diconの<components>タグ中に下記を追記する。
<include path="chronos-extension.dicon"/>
※ 公式に記述なし。

6. web.xml の<web-app>タグ中に下記を追記する。
<servlet>
    <servlet-name>chronosServlet</servlet-name>
    <servlet-class>org.seasar.chronos.extension.servlet.S2ChronosServlet</servlet-class>
    <load-on-startup>3</load-on-startup>
</servlet>
※ 公式に記述なし。

これでTomcatを起動する。記述に間違いがある場合はコンソールにログが出力されるので確認する。当たり前だが、エラー発生時にはException名よりもどのファイルの読み込み時に落ちているのかに着目して追うと原因を突き止めやすい。

【環境】

Java SE7
Seasar2.4.45
S2Chronos1.0.0
※ そもそもJava SE5までしかサポートしていない模様。

[Java] アプリケーションの実行環境(ホスト名, IPなど)を取得する

java.net.InetAddressクラスを利用することでアプリケーションの実行されているマシン名を取得できる。
import java.net.InetAddress;

// ホスト名取得はこれだけ
System.out.println(InetAddress.getLocalHost().getHostName());
他にもIPアドレスを取得したりできる。

Webアプリケーションだと、AP起動時にホスト名から実行されている環境を判定してメモリに保持しておくなどの使い道がありそう。 ソースで環境毎の分岐を記述することで、環境依存ファイルを少し減らせる…かも。
例えば、起動時に以下のようなクラスをロードしておく。Singletonだと良さそう。
import java.net.InetAddress;
import java.net.UnknownHostException;

public class RuntimeEnvironment {

 private static RuntimeEnvironment instance = new RuntimeEnvironment();
 private RuntimeEnvironment() {}

 private static String hostName;
 private static InetAddress inetAddress;

 public static void init() {
  try {
   inetAddress = InetAddress.getLocalHost();
  } catch (UnknownHostException e) {}
  hostName = inetAddress.getHostName();

 }

 public static String getHostName()             {return hostName;}
 public static InetAddress getInetAddress() {return inetAddress;}

        // 以下、用意する環境を表す列挙型を定義するなど…

}




【環境】

 Java SE7

2014年6月28日土曜日

柿喰う客『へんてこレストラン』@北とぴあ 観劇

東京都北区にある北とぴあにて柿喰う客の『へんてこレストラン』を観劇。6/28(土)17:00~の回。

内容は宮沢賢治の『注文の多い料理店』を中屋敷法仁氏が舞台用にアレンジしたもの。
また本作は「こどもと観る演劇プロジェクト2014」の一つであり、通常の演劇では入場を規制される未就学児童も観劇可能で、上演時間も45分と短くなっている。
ストーリーは知られている、かつこどもの観劇を前提とする中でどんな演出がなされるのか、期待して観た。

柿喰う客の作品は年始頃に『世迷言』を観たのみ。
それがとにかく衝撃的で、観劇でいちばん感動した体験はあの時だったかも。


で、今回。
こども向けだと若干表現も甘くなるかな~と思ったが、全くそんなことは無かった。

言葉や動きのスタイリッシュさは以前に観た時の印象と変わらなかったし、題材のストーリーよりもどんな表現が次に出てくるのだろうという期待続きであっという間に終わってしまった。最前の桟敷に座っているこども達(3~5歳ぐらい?)も終始見入っていて、楽しんでいるように見えた。


中屋敷法仁氏のアフタートーク(毎回やっているらしい)でも面白い話が聞けた。

「リズムも目配せもキューも無い中で、複数人の役者が同時に発生をしたり動いたりするのは、いったいどうやっているのですか?」

柿喰う客がおそらくいつもやっている表現の一つに関する質問。これに対し、
「以前はリズムに合わせるとかブレスするタイミングで合わせてたりを考えていたけど、いつの間にか長く一緒にやってきた役者どうしで、自然にできるようになっていた。どうせできるならこっちの方が表現としてインパクトも大きいし、じゃあ採用しよう、と。どうしてできているのかもよかわかってないから他の人に教えたりできない(方法論化できていない)けれども」 (うろ覚え)
とのこと。
何も無いところで合わせる、っていうのはバンド演奏でもまれにあるが、やっぱり難しい。というか狙ってやってる様な演奏は殆ど知らない。
でもその分インパクトがある。これを完全に計算して組み込んでいるからやっぱり"凄み"がある。

他にも能や狂言から表現を取り入れているという話や、"見える言葉、聞こえる身体"(うろ覚え)という柿喰う客のモチーフのようなワードも聞けた。
後者は成る程、柿喰う客にぴったりの言葉だな、と思った。

今後の公演も見逃さないようにしたい。

2014年6月15日日曜日

『BLUE GIANT』で定義される"ジャズ"と、明確に区分される人々

ビッグコミックススペシャルで連載中の音楽漫画、石塚真一『BLUE GIANT』1~2巻読んだ。
世界一のジャズプレイヤーを目指す高校生、宮本大のストレートでパワフルな青春・成長譚。面白い。

"ジャズ"の定義

読んでまず感じたのは、作品世界における"ジャズ"が明確に定義されていること。
良く分からない、難しい、オトナの、おしゃれな… 一般的によく聞かれるジャズへの偏見を、"ジャズ"を知らない側の人間に言わせた上で、「みんなそう言うけど、ハゲしくて、自由な音楽が"ジャズ"なんだ」と大が一蹴する。

そう、「ハゲしくて、自由な音楽」。これがこの世界における"ジャズ"の定義、本懐だ。

二分される登場人物と大

『BLUE GIANT』の世界ではこの本懐をわかっているか否かで、登場人物の立ち位置が明確に分断されている。
そう、この世界の登場人物は"ジャズ"を知っている人と知らない人に完全に二分されているのだ。
もちろん主人公の大は前者に属する。

ただし、大はその中でも特殊な能力を持っている。演奏によって"ジャズ"を知らない人間に"ジャズ"を知らせる、伝える力だ。

"ジャズ"を知っている人は大の才能(本懐を理解し、表現できる能力)を見抜くし、知らない人(友達の周平、同級生の女の子)は大によって本懐に触れさせられ、"ジャズ"を感覚で理解し、大たちのいる領域へと踏み入れることになる。

このシーンこそがこの漫画の最も"熱い"ところで、漫画的にも力を込めて描かれている。
音の出ない漫画でその熱量、才能、感動をどう描くかがやはりポイントで、今のところかなり良い。

最初から大の才能は顕在化しているし、コミックスの巻末に挟まれる後日譚から既におおよその結末は読者に知らされている。
それでも、大の才能や彼を取り囲む環境がどんな過程を経るのか、どのような人間を、ジャズを描くのか、という疑問が好奇心を惹くし、今後の展開が楽しみ。


1点、今後の展開で気になるのは、大たちの"ジャズ"以外のジャズは描かれないのだろうか、ということ。そもそも「ジャズとは何か」という問いに正解は無い。どのような解釈も自由なはずだが、もしこの漫画で異なる定義のジャズを信じる人々が描かれない、または登場してもこの物語からは消えていく、言い換えれば「切り捨てられていく」のであれば残念だ。

そういった人々とぶつかっていき、相対化することで大たちの信じる"ジャズ"がより熱く、激しく描くことができるはずだから。

五反田団『五反田怪団 ザ・ベスト』@アトリエヘリコプター 観劇

アトリエヘリコプターにて五反田団の『五反田怪団 ザ・ベスト』を観劇。6/8(日)19:00~の回。

『五反田怪団』シリーズは毎夏に行われ、今年で10年目?になる人気シリーズであり、今回はこれまでの怪団の中でも選りすぐりの怪談を集めたザ・ベスト、とのこと。
僕自身が演劇を観始めたのは昨年からなのだが、五反田団は今回で3回目になる。毎度面白いので追いかけている。

どこまでが演技か

毎度見ていて凄いな、と思うのが「どこまでが演技でどこまでが素の振る舞いなのか」その境界線を観客に意識させないところ。
台詞を噛むことや言いよどみ、手を組み直したり髪に触れる行為。そうした言葉・振る舞いの中でもノイズに相当するものをあえて(?)セーブしないことでリアリティが増すし、それらを含めて劇として成立させているのはやはり計算だろうか。
このように身体のノイズで演技の境界をぼかす手法は全ての劇に有効だとは思わないが、今回の怪談やコメディにおいてはとても有用だと思う。

ユーモラスであることと笑わせることは違う

また、五反田団を観ていて思い出したのは町山智浩氏のこんな言葉。
ユーモラスに撮ることと笑わせることはまったく違う。ユーモラスな雰囲気に撮るだけではかえって寒くなるから、きちんとギャグを入れなきゃいけない
日本の監督はよくココを間違えるからダメだ~というような話。

邦画のダメさみたいなのはよく知らないので置いといて、確かに演劇においてもそういう勘違いや寒さみたいなのを感じることはあるし、それがあると自分と作品との距離が一気に開くのを感じ、冷めてしまう。
この観点で五反田団を観てみると、きちんとギャグを入れてきてくれるな~と思う。笑いどころに困ったまま白けることもなく、安心して笑える。こういうのがコメディだと思えるし、人にも薦めたくなる。


この演劇を観てなんとなく自分も怪談を語りたくなって、『ザ・ベスト』の中からいくつか拝借して友人に話ったら割りと盛り上がったのもあり、行って良かった。

2014年6月5日木曜日

本日のGot to be real

小学区の時にリンダって呼ばれてた女の子に唇が酷似しているCheryl Lynnだが、今日は32回ぐらい彼女の『Got to be real』を聞いた。「今日何してた?」と尋ねられたら間違いなく「Cheryl Lynnの『Got to be real』聞いてた」って答えると思うので、そういう状況でこそ"本日の1曲"の名を与えていきたい。







ベースラインが骨になっていて、聞きっぱなしでも飽きない。

Victor Wooten的に言うと、"本物のグルーヴには飽きが来ない"。



"グルーヴ"を聞く!!


2014年5月30日金曜日

[JavaScript] JScriptでメール送信ができる (Outlook, Gmail)

宛先や内容は毎回異なるが、ほぼ定型のメールを毎月送る定常業務がだるい~
ので自動化しようと調べてみたら、Jscriptでメール送信ができると知った。

[Outlook]
OutlookとWSHでメール送信 - くじらはんど★ブログ

[Gmail]
定型メールの送信を自動化する~GmailとJavaScriptの華麗な連携技(第13回)《クジラ飛行机「仕事に役立つJavaScript入門」》

社用メーラはOutlookなのでとりあえず上記を試してみたところ、難なく成功。
社員番号がエイリアスになっているので、宛先の設定も楽。

即バッチ作って来月から運用する。

2014年5月24日土曜日

手拍子とグルーヴ

グルーヴ=?



いつどこで聞いたか完全に忘れたけれども、「手っ取り早くグルーヴを感じたり作り出したいのなら、グルーヴのある演奏に合わせて手拍子をすることだ」というアイデアが離れないでいる。

ここから「グルーヴしたけりゃその時はこっちから手拍子するわ」、グルーヴに対する-良く言えば-積極性または-悪く言えば-強制性の否定が個人の音楽鑑賞・体験スタイルが形作られた。

このスタイルを軸に、ミュージシャンのライブで煽られる手拍子には長らく頑として拒否する姿勢を保ってきた。というより、グルーヴを表に押し出さない演奏またはグルーヴの無い演奏を前に手拍子"してあげる"ことの虚しさを払拭できずにいた。

手拍子は一体感を産み、これはグルーヴの有無に依らないと思う。ともすればその一体感が音楽的な体験(ここで言うグルーヴにより生み出されるもの)なのか、当事者間のリレーション(ミュージシャンとリスナーの間、またはリスナー同士)へのアウェアネスなのか、その境界は曖昧になる。この境界線がぼやけていることこそ、ショウビジネスとの親和性の高さに紐付いているのは別の話だが、時偶この事実によって音楽的な体験が矮小化されているのではないかと思うこともある。矮小化とは言わないまでも、比率やプライオリティを下げられているように感じる。


ここまではリスナー側の話だがステージに立つとまた話が変わる。
観客に手拍子をしてもらうと気持ちが良い。手拍子でなくても同調的な行動をとってもらうと、ライブそもそもの高揚感もあいまって、自分たちを中心に生み出される大きなエネルギーを感じる。はっきり言ってこれはやみつきになる。煽りたくなるのも当然に思えてくる。


…とまで書いて何が言いたいのかよくわからなくなった。。

2014年5月21日水曜日

読みたい記事メモ

Qiitaのメール、個人的にいつも見失う


[SQL] IN句の検索リストに列名を指定する

SQLのIN句の説明や実際の使用例を見ていると
[列名] IN ([検索リスト])
という記述が多い。
しかし、検索値をIN句の前に持ってきて列名を列挙することもできる。
[検索値] IN ([列名リスト])
この用法は、類似する情報を複数のカラムで持つような場合に使える。
--最高音か最低音がC#
'C#' IN (top_note, bottom_note)
あまり使いどころが無さそうに見えるが、正規化されていないテーブル設計を前にすると結構使えたり…。

2014年5月17日土曜日

Mac mini買った

Mac mini買った。
音楽編集とiPhoneアプリ開発が目的で、とにかく安値でMacの環境が欲しいと思って選択した。

「Mac miniは2012年から新作が出ておらず、そろそろ"来る"だろうからやめた方が良い」的な話は聞いていたけど、それにしても価格が魅力的だったのでまぁいいかという感じ。

Apple Days | Apple製品の発売周期まとめ


早速、Xcodeをインストールしててきとうに動かしてみたところ、何かしらの高揚感ある。

が、
初MacでOSに慣れてないとのと、Windows準拠キーボード使用のせい?で作業効率の低さがやばい。

当面は『詳細!Objective-C』読みつつ頑張る。
画像加工アプリでも作ってみよう。


【参考】

ゼロから始めるMacintosh開発環境構築(OS X Mavericks編)ーこれからプログラミングを始める人のためにー(1) | IT系のインターンシップならエンジニアインターン - 
初心者でも5分で作れそうなiPhoneアプリ講座 : IT速報 - 

[SQL] sum (case when ~)で異なる条件の集計をまとめて取得する

既存システムに参照だけのview(画面、帳票)を追加。
項目ごとの表示桁数はフォントや枠サイズを基準に定められたが、現行でその桁数を超えるデータがどれだけあるのかわからないというので調査することになった。
(順序が逆な気がするが)

やりたいこと


  • 表示する項目の文字数が指定の桁を超えるレコードの数を集計する
  • 対象の項目は複数あり、それぞれで指定の桁数(=条件)は異なる
  • 文字数制限とは別に、いくつかの条件で絞込も行う

最初に考えたのは以下のような感じ。
条件ごとにcountした結果を愚直に結合。

select *

from
 -- 名称が10文字を超えるレコードの件数
 (select
   '名称' as column_name
  ,count(*) as product_count
 from
  t_product p
 where
  p.color = 'red'  -- 共通条件
  and length(p.name) > 10
 )

 union all

 -- コードが4文字を超えるレコードの件数
 (select
   'コード' as column_name
  ,count(*) as product_count
 from
  t_product p
 where
  p.color = 'red'  -- 共通条件
  length(p.cd) > 4
 )

 -- 以下、似たような条件が続く...

実行計画とったら非常に遅い、かつwhere句の条件が重複しているなど"何か悪いことをしている"感が凄かったので、条件付きで集計するにはSUM(CASE WHEN ...)を参考に考えなおした。

select
  count(*) as 総数
 ,sum(case when length(p.name) > 10 then 1 else 0 end) as 名称
 ,sum(case when length(p.cd) > 4 then 1 else 0 end) as コード
 -- 以下、似たような条件が続く...
 
from
 t_product p
where
 p.color = 'red'


もともとwhere句に書いていた項目ごとの条件をcase whenにブチ込みつつ、共通条件は共通化させる。だいぶすっきりしつつ実行計画もまぁまともな数値が出たので良かった。

これにさらに区分ごとの条件なんかを足していき、最終的には以下のようなSQLをブン投げて調査を終えた。

select
  count(*) as 総数
 ,case when p.type = 'a' -- aの場合はnameのlengthだけで判断
            then sum(case when length(p.name) > 10 then 1 else 0 end)
       when p.type = 'b' -- bの場合はnameとcolorを結合したlengthで判断
            then sum(case when length(p.name || p.color) > 15 then 1 else 0 end)
       else -1 -- a,b以外のtypeの場合は集計対象外
       end as 名称
 ,sum(case when length(p.cd) > 4 then 1 else 0 end) as コード
 -- 以下、似たような条件が続く...
 
from
 t_product p
where
 p.color = 'red'
group by
 p.type
order by
 p.type

今回はまさしく↓状態だった
「カウントする=COUNT関数」しか頭になく…(以下略)

【環境】

oracle 11g

【参考】

条件付きで集計するにはSUM(CASE WHEN ...)
MySQLでの条件付きSUM,COUNT

【2014/6/7追記】

上記のテクニックが最近読み始めた『達人に学ぶSQL徹底指南書』に載っていた。

曰く、
WHERE句で条件分岐させるのは素人のやること。プロはSELECT句で分岐させる。

実践的なパターンが多く掲載されており、常々SQL力の不足を感じていた自分には丁度良い。

2014年5月10日土曜日

[Perl] 画像を指定の枠に収まるようにリサイズ&余白を透明化

業務で必要になり、Perlでの画像加工処理を書いた。

実現したいこと

  1. 画像のアスペクト比を維持したまま、指定したサイズの枠に収まるようにリサイズ
  2. 指定したサイズの枠の中心に画像を貼り付け、余白は透明にする

今回は透明のキャンバスを作り、その上にリサイズした画像を貼り付けることで実現する。
そのコードが下記。

use Image::Magick;

my $src = "cat.png";       # 読み込むファイル名
my $dst = "dst.png";       # 出力する画像ファイル名
my $canvas_width = '600';  # 枠の幅
my $canvas_height = '400'; # 枠の高さ
 
# 透明のcanvasを作成
my $canvas = Image::Magick->new;
$canvas -> Set(size=>$canvas_width . 'x' . $canvas_height);
$canvas -> ReadImage('xc:white');
$canvas -> Transparent(color=>'White');

# 画像を読み込む
my $src_image = Image::Magick->new;
$src_image -> Read("$src");
my($src_width, $src_height) = $src_image -> Get('width', 'height');

# 画像とcanvasのアスペクト比を比較
my $canvas_ratio = $canvas_width / $canvas_height;
my $src_ratio = $src_width / $src_height;
my $magnification = 0;

# 画像がcanvasに対して縦長の場合
if ($canvas_ratio > $src_ratio) {
 # 高さの比を倍率にする
 $magnification = $canvas_height / $src_height;

# 画像がcanvasに対して横長、もしくは完全一致の場合
} elsif ($canvas_ratio <= $src_ratio) {
 # 幅の比を倍率にする
 $magnification = $canvas_width / $src_width;
}

# 倍率を指定してリサイズ
$src_image -> Resize(width=>int($src_width  * $magnification),
     height=>int($src_height * $magnification));

# 画像を重ねる
$canvas->Composite(image=>$src_image, compose=>'over', gravity=>'Center');

# 画像を出力
$canvas->Write("$dst");


【実行結果】

この猫の画像(1600x1200)を


600x400の枠に収めようとすると、出力結果はこんな感じになる。
クリックするとリサイズの効果と、左右に透明の余白があることがわかる(はず)。

とはいえあまりにわかりにくいのでExcelに貼り付け、画像に枠線を付けてみたのが↓。


Perlは半年以上前にいくつか手探りでバッチ作ったけど、それを除けばほとんど書いたことなし。
今回は文法をおさらいしつつ書いたけど、いまいちPerlの文化というか作法みたいなのはわからず…。

そして、Image::Magick便利。

【環境】

ActivePerl 5.16.3
Image::Magick 6.8.9

【参考】

Matsup's blog: FreeBSDでPerlMagick(その4)図形の描画と画像の加工
PerlMagickで画像の大きさを変更する(Image::Magick) | ぺんラボ
Perl::ImageMagickでよく使うコマンドとサンプル | くろひつじのメモ帳


【追記(2014/05/11)】

そういえば拡張子によっては透過って対応してないような…と思い、png/gif/jpgと試していった。
そしたらjpgだと余白が透過になっておらず、調べるとjpgは透過できないぽい。

透過背景とか使いたい場合は対応している拡張子で保存するようにする。

また、Image::MagickのRead/Write処理では記述した拡張子で読み込み/保存を行ってくれるとのこと。



2014年5月5日月曜日

[Java] POIで、読み込んだExcelファイルから図形を取得して値をセットする

Excelファイル(※2007以降の.xlsx形式)から目的の図形を取得し、値をセットする。
今回はテキストボックスを取得してセットするサンプル。

既に対象のWorkbookとSheetを取得している状態から。
// 図形描画の為のXSSFDrawingから図形のListを取得
XSSFDrawing drawing = sheet.createDrawingPatriarch();
List<XSSFShape> shapeList = drawing.getShapes();

// Listから目的の図形を探索
for (XSSFShape sh : shapeList) {
  // (1)実際の型を確認
  if (sh instanceof XSSFSimpleShape) {
     XSSFSimpleShape ss = (XSSFSimpleShape) sh;
     // (2)テキストの値をkeyに対象かどうか判断
     if (ss.getText().equals("key")) {
      ss.setText("value you want to set");
     }
  }
}

(1)Listで取得されるオブジェクトはXSSFShapeのサブクラス(※)であり、検査せずにSimpleShapeとして扱おうとするとClassCastExceptionが発生する。
 ※こいつら。↓
  XSSFConnector, XSSFGraphicFrame, XSSFPicture, XSSFShapeGroup, XSSFSimpleShape。

(2)APIDocなんかを読み漁ったけれども、定義した名前から図形を取得する方法がわからず。とりあえずテキストから判断するやり方で記述。


【環境】

 POI 3.10
 Java SE7

【参考】

XSSFSimpleShape (POI API Documentation)


[追記 2014/5/7] 

上記のやり方で値をセットすると、図形にもともと設定されていたフォントや揃方がクリアされてデフォルト値になってしまうことがわかった。

もともと設定されていたフォントなどを維持したままテキストのみを置き換える場合は下記のようにテキストを分解し、テキストの最小単位(TextRun)に対して操作を行わなければいけないらしい。

// 上記の11行目から
if (ss.getText().equals("key")) {
  for (XSSFTextParagraph p : ss.getTextParagraphs()) {
   for (XSSFTextRun r : p.getTextRuns()) {
    r.setText("value you want to set");  // ※1
   }
  }
}
※1 改行を含む文字列をブチ込んでも大丈夫だった。だがParagraphの扱いがよくわかっていないので、複数行を操作する場合はもう少し工夫が必要なのかもしれない。

FontはFontクラスで管理してたり、AlignはTextParagraphで管理していたり。Excelの実装自体がそうなのかもしれないけど、Excel上の設定と各オブジェクトの結びつきがわかりづらく、直感的に操作しづらい。。

2014年5月2日金曜日

[Java] enum型にデータと振る舞いを持たせる

Effective Java第二版でJavaの勉強中。

「項目 30  int定数の代わりに enum を使用する」にて紹介されている、
"enum型にデータと振る舞いを持たせる"コードを真似して書いてみた。
// 面積の単位ごとのデータ、メソッドを定義
private enum Unit {
HEIBEI ("㎡"){
  String getArea(double area) {
   return area + this.toString();
  }
 },
 TSUBO ("坪"){
  String getArea(double area) {
   return area * 0.3025 + this.toString();
  }
 };

 private final String unitName;

 // コンストラクタ
 Unit(String unitName) { this.unitName = unitName; }

 // すべての定数にオーバーライドを強制する
 abstract String getArea(double area);

 // カスタム文字列表現
 @Override
 public String toString() {
  return unitName;
 }


 // 一意の文字列表現から定数を取得できるようMap化しておく
 private static final Map stringToEnum = new HashMap<>();
 static {
   for (Unit unit : values())
    stringToEnum.put(unit.toString(), unit);
 }

 // 一意の文字列表現から定数を取得する(toStringと対)
 public Unit fromString(String unitName) {
  return stringToEnum.get(unitName);
 }
}

// 定義したenumを利用する
public static void main(String[] args) {
 double area = 320.25;

 System.out.println(Unit.HEIBEI.getArea(area));
 System.out.println(Unit.TSUBO.getArea(area));
}
実行結果
320.25㎡
96.875625坪

これまでenum型については、
バッドプラクティスとして知られる"int enumパターン"(下記)の代用として定数を列挙する、ぐらいにしか使ったことがなかった。。
// No More int enum pattern!!
public static final int HEIBEI = 1;
public static final int TSUBO  = 2;

2014年5月1日木曜日

[Java] POIで、名前が定義されているセルに値をセットする

Excelファイル(※2007以降の.xlsx形式)から名前が定義されているセルを取得し、値をセットする。

既に対象のWorkbookとSheetを取得している状態から。
XSSFName name = workbook.getName("cell's Name");
CellReference ref = new CellReference(name.getRefersToFormula());
XSSFRow row = sheet.getRow(ref.getRow());
XSSFCell cell = row.getCell(ref.getCol());
cell.setCellValue("value you want to set");

上記コードにて、単一のセルにも結合されたセルにも値をセットできることを確認済み。
結合されたセルは範囲で取得したりする必要があるかと思ったけど、今のところ問題無さそう。

また、存在しないセル名を指定している場合、1行目のworkbook#getNameはNullを返すので注意。

【環境】

 POI 3.10
 Java SE7

【参考】

POIで名前定義されているセルを取得する話 - kelkronsoの日記 -
POIで、名前定義の入ったカラムから値を取得。 - るいもの戯れ言 -

2014年4月30日水曜日

[Java] Apache POIで指定した範囲の中心に画像を貼り付けようとして挫折

下記の条件でExcelファイル(※2007以降の.xlsx形式)に画像を貼り付ける。(だいぶ限定的…)

1.画像を貼り付けるセル範囲が指定されている。
2.画像は指定された範囲内で、アスペクト比を保ったまま最大化する。
3.範囲は任意だが、指定された範囲のセルはすべて同じ幅であり、
 かつ指定された範囲のセルはすべて同じ高さとする。


こんな感じ。(水平・垂直方向が逆のケースもあり)


結論から言うと、完全にアスペクト比を保ったままの最適化は出来なかった。

上記図で言うmarginは画像貼り付け先の開始位置をずらしつつ、オフセットを指定することで構成されるが、オフセットの指定はint型でしか行えないことによる。(必要なオフセットは当然、小数の場合もある)

単純なことだが、それに気付くまでの軌跡は↓。。

// 画像とセル範囲のアスペクト比を比較
double imgRatio = (orgImgWidth / (double)orgImgHeight);
double cellRangeRatio = (cellRangeWidth / (double)cellRangeHeight);

// 高さを最大化し、水平方向位置を計算する
if (imgRatio < cellRangeRatio) {
  // 貼り付けられる画像の幅
  double imgWidth = (orgImgWidth * (cellRangeHeight / (double)orgImgHeight));

  // 余白の幅
  double margin = (cellRangeWidth - imgWidth) / 2 ;
  int offsetCol = (int)(margin /  cellWidth);
  imgStartCol = rcol1 + offsetCol;
  imgEndCol = rcol2 - offsetCol;
  int offset = (int)(XSSFShape.EMU_PER_PIXEL * (margin  %  cellWidth));
  dx1 = offset;
  dx2 = offset;

// 横を最大化し、垂直方向位置を計算する
} else if (imgRatio > cellRangeRatio) {
  // 貼り付けられる画像の高さ
  double imgHeight = (orgImgHeight * (cellRangeWidth / (double)orgImgWidth));

  // 余白の高さ
  double margin = (cellRangeHeight - imgHeight) / 2 ;
  int offsetRow = (int)(margin /  cellWidth);
  imgStartRow = rrow1 + offsetRow;
  imgEndRow = rrow2 - offsetRow;
  int offset =  (int)(XSSFShape.EMU_PER_PIXEL * (margin  %  cellHeight));
  dy1 = offset;
  dy2 = offset;
}

【環境】

 POI 3.10
 Java SE7

2014年4月29日火曜日

[JavaScript] 画像の一部を範囲選択してぼかす(もしくはその他の加工を行う)

ブラウザに表示される画像の一部を範囲選択してぼかす機能を実装したい。
まだ試してないけども下記なんかを組み合わせて実現できそう。

1.範囲選択

Jcrop - Deep Liquid - 

2.ぼかし(その他の加工も多く用意されている)

Pixastic: JavaScript Image Processing Library - 


と思ったらPixasticはIEじゃ動かない的な一文が。

Pixastic works by utilizing the HTML5 Canvas element which provides access to raw pixel data, thereby opening up for more advanced image effects. This is where the "experimental" part comes into play. Canvas is only supported by some browsers and unfortunately Internet Explorer is not one of them. 
とはいえこれがいつ書かれた文書なのか良くわからないので今度ちゃんと試してみる。





そういえば、
画像加工用のライブラリは大量にあるみたいだけど、範囲を指定して加工できるものはあまり無いような気がした。

2014年4月28日月曜日

BloggerのテンプレートにSyntaxHighlighter組み込んだ。

タイトル以上の情報なし。


下記サイトを参考に入れてみた。

Pirates of 富山湾: Bloggerにソースコードをきれいに載せる「SyntaxHighlighter」

なんか面倒なのかな…と思っていたけど3分ぐらいで設定終わって、即使えるようになった。
ありがとうございます。

[Java] Apache POI XSSFClientAnchor でoffset を指定して画像を貼り付ける

初POI。
EXCEL(.xlsx)ファイルに画像を貼り付ける際の offset の指定に苦戦。

画像の位置指定は XSSFClientAnchor クラスを用いて行う。
設定方法は下記の2通りが可能。

1.create時に位置指定を行う。

XSSFClientAnchor anchor = XSSFDrawing.createAnchor(
                          dx1, dy1, dx2, dy2, col1, row1, col2, row2);

2.create後に位置指定を行う。

XSSFClientAnchor anchor = XSSFCreationHelper.createClientAnchor();
anchor.setDx1(dx1);
anchor.setDy1(dy1);
anchor.setDx2(dx2);
anchor.setDy2(dy2);
anchor.setCol1(col1);
anchor.setRow1(row1);
anchor.setCol2(col2);
anchor.setRow2(row2);

※XSSFDrawing クラスに引数無しのcreateAnchorメソッドは無い模様。

開始位置・終了位置の指定

XSSFAnchor.setCol , setRowでcolumn・rowをそれぞれ指定する。
注意点としては、指定したセルの最右下の座標から開始されること。
anchor.setCol1(1);
anchor.setRow1(1);
anchor.setCol2(4);
anchor.setRow2(4);

と指定すると

と出力される。

また、左辺と上辺は罫線上に描画され、右辺と下辺は罫線に重ならない。


オフセットの指定

XSSFClientAnchor#setDx1, setDy1, setDx2, setDy2 で指定する。
これら setter の引数はjavadocには
the x coordinate within the first cell.
とあり、int型の引数が要求されているが、ピクセルなのかポイントなのかわからない。
適当な数字を入れても挙動の法則がわからなかったので、
The offsets are measured in EMUs (english metric units). There are 12700 emus in a point , see EMU_PER_PIXEL and EMU_PER_POINT constants in the XSSFShape class. 

To position a rectange with given width and height at a point (x,y) 
you need to transform all coordinates to Excel coordinate system, i.e 

x1 --> col1 + dx1 
y1 --> row1 + dy1 
x2 --> col2 + dx2 
y2 --> row2 + dy2 
EMUという単位で指定する、とのこと。
この数字はXSSFShape クラスに定義されており、1ポイント=12700EMU、1ピクセル=9525となっている。

その為、setColやsetRowで指定した開始位置から10ピクセルのoffsetを作りたい時は
setDx1(XSSFShape.EMU_PER_PIXEL * 10);
とすれば良い模様。


指定するdx1, dy1, dx2, dy2 はそれぞれ下記のようにオフセットを構成する。




【環境】

POI 3.10
Java SE7

【参考】

apache poi の HSSFClientAnchor について。 - 人工無脳が作りたかった
POI - User - How to calculate location of the shape in Excel 2007?
POI - Dev - Re: Anchor type for images in Excel