lazy val jar = packageTask(packagePaths, jarPath, packageOptions).dependsOn(compile) describedAs "Creates a jar file."sbt jarでjarファイルが作られます。
2011年2月9日水曜日
[Scala][sbt]DefaultWebProjectでwarではなくjarも作りたい
DefaultWebProjectだとsbt packageタスクでwarが作られますが、jarも作りたい時があった場合、こんな感じで。
2011年2月7日月曜日
[GAE] bulkloaderをGAE/Jで使う
python版appengine-sdkを使ってcsvファイルからデータをDatastoreにロードすることができます。
キーにidではなく文字列(name)を使用する場合は、import_transform: intは不要。
import_transformに他に指定できる例
日付: transform.import_date_time('%Y/%m/%d %H:%M')
固定値: import_transform: lambda x:1
数値変換: import_transform: lambda x:int(x)*100
※lambdaは引数の:の後にスペースを空けるとダメな様です
ロード用CSV
security-constraintの設定をしている場合、毎回管理者アドレス/パスワードの入力が必要です。
ローカルのdev_appserverだとエラーが出て動きませんでした…
こんな感じに反映されます。
※1万件だと約500秒(8分ちょっと)くらいかかりました(CPU Timeを無料Quotaの10%ほど消費します)
slim3を使っている場合、filterの設定があると、"ProtocolBufferDecodeError: corrupted"の様なエラーが出てしまうので一時的にコメントアウトして回避しました。(※他にいい方法があれば教えて下さい…
2/11追記: bulkload用にfilterをコメントアウトしたversionをデプロイしておいて、--url=http://latest.bulkload.{appid}.appspot.com/remote_api みたいに指定するといいかも
3/22追記:slim3ではなくscenic3の方の設定でした。matcherで/remote_apiを除外したらOK。
参考: Ikai Lan says / Using the bulkloader with Java App Engine
準備
- python版appengine-sdkをインストールする
web.xmlにremote_api用のServletの設定を書く
<servlet> <servlet-name>remoteapi</servlet-name> <servlet-class>com.google.apphosting.utils.remoteapi.RemoteApiServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>remoteapi</servlet-name> <url-pattern>/remote_api</url-pattern> </servlet-mapping>security-constraintも追加しておいた方が良さげ。
<security-constraint>
<web-resource-collection>
<url-pattern>/remote_api</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
ロード設定用のyamlファイルを書く
python_preamble:
- import: base64
- import: re
- import: google.appengine.ext.bulkload.transform
- import: google.appengine.ext.bulkload.bulkloader_wizard
- import: google.appengine.api.datastore
- import: google.appengine.api.users
transformers:
- kind: Scores
connector: csv
connector_options:
encoding: ms932
property_map:
- property: __key__
external_name: id
import_transform: int
- property: name
external_name: name
- property: score
external_name: score
import_transform: transform.none_if_empty(float)
日付: transform.import_date_time('%Y/%m/%d %H:%M')
固定値: import_transform: lambda x:1
数値変換: import_transform: lambda x:int(x)*100
※lambdaは引数の:の後にスペースを空けるとダメな様です
ロード用CSV
id,name,score 1,Alice,5.0 2,Bob,2.5 3,Caroline,
ロード用コマンド
appcfg.py upload_data --filename=test.csv --config_file=test.yml --url=http://{appid}.appspot.com/remote_api --application={appid} --kind=Scores -v
※{appid}はアプリケーションIDに置き換えるsecurity-constraintの設定をしている場合、毎回管理者アドレス/パスワードの入力が必要です。
ローカルのdev_appserverだとエラーが出て動きませんでした…
こんな感じに反映されます。
※1万件だと約500秒(8分ちょっと)くらいかかりました(CPU Timeを無料Quotaの10%ほど消費します)
その他注意点
3/22追記:slim3ではなくscenic3の方の設定でした。matcherで/remote_apiを除外したらOK。
参考: Ikai Lan says / Using the bulkloader with Java App Engine
2011年1月15日土曜日
[Blogger] スマートフォン用テンプレートを有効にする
いつの間にかβ版としてスマートフォン用テンプレートの機能が追加されてたので有効にしてみた。
draft.blogger.com の方からログインするとβ版機能が使えます。
有効にするには、設定 > メールとモバイル > モバイル テンプレートを表示する で はい を選ぶだけ。スマートフォンの場合は自動でリダイレクトしてくれるようです。
ガラケーからもurlの最後に?m=1を付けるとモバイル用テンプレートで表示してくれましたが、ページ遷移にjavascriptが使われているようで残念ながら記事一覧以降進めませんでした…。
draft.blogger.com の方からログインするとβ版機能が使えます。
有効にするには、設定 > メールとモバイル > モバイル テンプレートを表示する で はい を選ぶだけ。スマートフォンの場合は自動でリダイレクトしてくれるようです。
ガラケーからもurlの最後に?m=1を付けるとモバイル用テンプレートで表示してくれましたが、ページ遷移にjavascriptが使われているようで残念ながら記事一覧以降進めませんでした…。
2011年1月12日水曜日
[Lift] Liftで処理したくないリクエストの設定
web.xmlで全てのリクエストがLiftで処理されるようになっているので、Lift以外のサーブレット等で処理したい場合に困ります…
Boot.scalaのdef bootにこんな感じで書けばOK。
※filter-mappingで除外ルールが書ければいいんだけど…
<filter-mapping> <filter-name>LiftFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Boot.scalaのdef bootにこんな感じで書けばOK。
LiftRules.passNotFoundToChain = true
LiftRules.liftRequest.append {
case Req("_ah" :: _, _, _) => false
case Req("remote_api" :: _, _, _) => false
}
※filter-mappingで除外ルールが書ければいいんだけど…
2011年1月1日土曜日
[Scala] sbt-appengineなプロジェクトをIntelliJ IDEAでデバッグ
@teaplanetさんにヒントいただいてIDEAのsbt consoleでdev-appserver-startできるようになったので、IDEA上でブレークポイントで止めたりできるように設定してみた。
この設定でsbt consoleからdev-appserver-startするとリモートデバッガで接続できる状態で起動するので、後はIDEAからデバッガ接続する。
IDEAのメニューからRun -> Edit Configurations -> [+] -> Remote を選んで、Nameは適当に、PortにdevAppserverJvmOptionsのaddress=xxxxで指定したポートを入れる(↑の例だと2011。適当に開いてるポート設定すればOK)。
設定したら、Run -> Debug... で選んでデバッグ開始するとdev-appserverのJVMにアタッチされてブレークポイントで止まってくれる。
※Before launchの"Run sbt action"でdev-appserver-startが指定できればsbt consoleからいちいちdev-appserver-startしなくても一発で起動できそうだけど一覧に出てこないし、直接指定してもダメでした…
参考:sbt-appengineの基本的な設定等は"sbtでGAEをする場合の注意点など色々。"が参考になります。
class MyProject(info: ProjectInfo) extends AppengineProject(info) {
//... 中略
//APPENGINE_SDK_HOME設定の代わり
override val appengineSdkPath = Path.fromFile("/Users/pomu0325/dev/appengine-java-sdk-1.4.0")
//dev-appserver-startの際のJVMオプション
override val devAppserverJvmOptions = List("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,address=2011,suspend=y") ++ super.devAppserverJvmOptions
}
この設定でsbt consoleからdev-appserver-startするとリモートデバッガで接続できる状態で起動するので、後はIDEAからデバッガ接続する。
IDEAのメニューからRun -> Edit Configurations -> [+] -> Remote を選んで、Nameは適当に、PortにdevAppserverJvmOptionsのaddress=xxxxで指定したポートを入れる(↑の例だと2011。適当に開いてるポート設定すればOK)。設定したら、Run -> Debug... で選んでデバッグ開始するとdev-appserverのJVMにアタッチされてブレークポイントで止まってくれる。
※Before launchの"Run sbt action"でdev-appserver-startが指定できればsbt consoleからいちいちdev-appserver-startしなくても一発で起動できそうだけど一覧に出てこないし、直接指定してもダメでした…
参考:sbt-appengineの基本的な設定等は"sbtでGAEをする場合の注意点など色々。"が参考になります。
2010年12月31日金曜日
[Lift] Lift2.2でCookieが無い場合にjsessionidがリンクに付加されない
#658 Supressing URL rewriting for jesessionid from Lift の修正により、デフォルトでjsessionidが付かないように動作が変わっています。
Boot.scalaで、
Liftで携帯サイト作ってる人とかはアップデートの際に要注意!
Boot.scalaで、
LiftRules.encodeJSessionIdInUrl_? = trueしてやればOK。
Liftで携帯サイト作ってる人とかはアップデートの際に要注意!
2010年12月30日木曜日
[Scala] dispatchでContent-Length付きのmultipartなPOSTする方法
とある写真投稿サービスのAPIにdispatch(0.7.8)を使って実装しようとした時のこと。APIのレスポンスでContent-Lengthが無いって怒られました。
dispatch-mimeを使うとmultipart/form-data形式でPOSTができるのですが、普通に実装するとContent-Lengthを送ってくれないようです。
ソースコメントにも書いてあるし。
Fileが引数の方を使えば良さげだけどGAEからだとFile使えません。dispatchのソースとapache-httpclientのjavadoc眺めて工夫したらできました。
※ただし、ByteArrayBodyはhttpclient 4.1(現在BETA1)から追加されるクラスなので4.1のjarを使わないとダメ(dispatch 0.7.8のdependencyはhttpclient 4.0になってた)。
sbtならこんな感じで。
dispatch-mimeを使うとmultipart/form-data形式でPOSTができるのですが、普通に実装するとContent-Lengthを送ってくれないようです。
ソースコメントにも書いてあるし。
Note that when using an InputStream generator, chuncked encoding will be used with no Content-Length header
Fileが引数の方を使えば良さげだけどGAEからだとFile使えません。dispatchのソースとapache-httpclientのjavadoc眺めて工夫したらできました。
import dispatch._ import dispatch.Http._ import dispatch.mime.Mime._ import org.apache.http.entity.mime.content.ByteArrayBody var req = ... //普通にdispatchのRequest作る req = req next req.add(paramName, new ByteArrayBody(data, contentType, filename)) //ByteArrayBodyを指定
※ただし、ByteArrayBodyはhttpclient 4.1(現在BETA1)から追加されるクラスなので4.1のjarを使わないとダメ(dispatch 0.7.8のdependencyはhttpclient 4.0になってた)。
sbtならこんな感じで。
val httpmime = "org.apache.httpcomponents" % "httpmime" % "4.1-beta1"
登録:
投稿 (Atom)
