[Scala]protectedの挙動

protectedの挙動ですが、まず

scalaでは、class とか object のメンバーはデフォルトではすべてパブリックとして定義されます
[scala]object PublicObject {
  val publicVal
  var publicVar
  def publicMethod = 1
}[/scala]
この例では、3つのメンバーは全部publicとして定義される

privateとprotectedは、Javaに良く似ています。
privateはJavaとほぼ同等の動きですが、protectedは劇的に異なります。

一つ目の違いは、protectedは2つの形式を持つことが出来ます。
protectedとprotected[foo]
※fooはclass、package、objectなど

二つ目の違いは、パラメータなしのprotectedは自身とサブクラスからのみ参照可能
[scala]scala> class Class1 {
     | protected def pMethod = "protected"
     | }
defined class Class1
scala> class Class2 {
// Class2はClass1のサブクラスでは無いので、pMethod にはアクセス出来ません。
     | new Class1().pMethod
     | }
<console>:6: error: method pMethod cannot be accessed in Class1
       new Class1().pMethod
                    ^
scala> class Class3 extends Class1 {
// ここがJavaと違うところで、pMethodにはアクセス出来ません。
     | new Class1().pMethod
     | }
<console>:6: error: method pMethod cannot be accessed in Class1
       new Class1().pMethod
                    ^
scala> class Class3 extends Class1 {
// pMethodにアクセス出来ます。
     | pMethod
     | }
defined class Class3[/scala]
パラメータありのprotectedの場合
パラメータに指定されたクラスからは参照できるようになります
[scala]scala> class Class1 {
// protected[Class1] は、privateと同等
     | protected[Class1] def method() = println("hi")
     | method()
     | }
defined class Class1

scala> new Class1()
hi
res0: Class1 = Class1@dc44a6d

// このmethodは、Class1からのみアクセスが出来ます。
scala> class Class2 extends Class1 { method() }
<console>:5: error: not found: value method
       class Class2 extends Class1 { method() }
                                     ^
scala> object Module {
     |   object Inner1 {
     |     protected[Inner1] def innerMethod = println("hi")
     |     protected[Module] def moduleMethod = println("moduleMethod")
     |
     |     object InnerInner {
     |       // InnerInner は Inner1 の中にあるので アクセス可能
     |       def callInner = innerMethod
     |     }
     |   }
     |   // moduleMethod は protected[Module] なので、Module内からはアクセス出来ます。
     |   def callModuleMethod = Inner1.moduleMethod
     |
     |   object Inner2 {
     |     // Inner1.moduleMethod は protected[Module] ですが、Inner2の中なので、moduleMethodはアクセス可能です。
     |     def callModuleMethod = Inner1.moduleMethod
     |   }
     | }
defined module Module
scala> Module.callModuleMethod
moduleMethod
scala> Module.Inner1.InnerInner.callInner
hi
scala> Module.Inner1.innerMethod
<console>:6: error: method innerMethod cannot be accessed in object Module.Inner1
       Module.Inner1.innerMethod
                     ^
scala> Module.Inner1.moduleMethod
<console>:6: error: method moduleMethod cannot be accessed in object Module.Inner1
       Module.Inner1.moduleMethod[/scala]

[Scala]MD5 ハッシュ値

ScalaでMD5を生成するには…

Javaのライブラリを呼び出して生成することになります。
[scala]import java.security.MessageDigest
val digestedBytes = MessageDigest.getInstance("MD5").digest("arekore".getBytes)
digestedBytes.map("%02x".format(_)).mkString[/scala]
Rubyの場合は
[scala]require ‘digest/md5’
Digest::MD5.new.update(‘arekore’)[/scalaa]
となります。

番外で、ScalaのLiftでは、md5(in: String)というヘルパーがありますが、これはBase64エンコードしてmd5生成しているような感じなので、Rubyでのmd5値とは一致しません。

なので、一致させたい場合は
[scala]def myMd5(in: String): String = md5(in.getBytes).map("%02x".format(_)).mkString[/scala]
とする必要あります。

もう一つ番外で

ScalaのMessageDigestで使えるアルゴリズムの一覧を得るには
[scala]Security.getAlgorithms("MessageDigest")[/scala]
とする

[Scala]派生クラスでtype aliasの指定を強制

abstractなclass とか trait に、型指定のないtype aliasを書くと、派生クラスでこのtype aliasの定義を強制します。
[scala]abstract class Oya {
// このクラスを継承した派生クラスでは、Xのtype aliasを明示しなければならない。
type AT

// X型はこのクラス内で使用可能。
var x:AT
def getAt:AT = x
}

class Ko extends Oya {
KoType =>
type AT = KoType
}[/scala]

Ubuntu 10.04にSubversionサーバを入れる

設定内容

  • 9000番ポートでsvnリポジトリを公開
  • svnリポジトリのデータは/var/svn_dataに保存
  • リポジトリ名はrepoで公開

まずはSubversionのサーバモジュールをインストール

[shell]sudo apt-get install subversion libapache2-svn[/shell]

/etc/apache2/sites-availableに移動

[shell]cd /etc/apache2/sites-available[/shell]

subversion という名前でファイルを作成

中身を

 

[text]
<VirtualHost *:9000>
ServerAdmin webmaster@localhost

<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/svn_data>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>

<Location />
DAV svn
SVNParentPath /var/svn_data
</Location>

ErrorLog /var/log/apache2/subversion-error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog /var/log/apache2/subversion-access.log combined
</VirtualHost>[/text]

とする

subversionをenableする

[text]sudo a2ensite subversion[/text]

/etc/apache2に移動

[text]cd /etc/apache2[/text]

ports.conf ファイルを開いて、9000番ポートをリッスンするように設定(以下を追加)

[text]Listen 9000[/text]

svnリポジトリのデータディレクトリを作成

[text]cd /var
sudo mkdir svn_data[/text]

svnリポジトリの作成

[text]cd /var/svn_data
svnadmin create –fs-type bdb repo[/text]

リポジトリの所有者をapacheの実行ユーザと同じ物に変える

[text]sudo chown -R www-data:www-data svn_data[/text]

apacheの再起動

[text]sudo apache2ctl restart[/text]

リポジトリの接続確認

http://localhost:9000/repo

[Scala]Scala + Liftで、JNDIでデータベースに接続する時に、JNDI名を変えて接続する

前回「[Scala]Scala + Liftで、GlassFishの接続プールを使う」の中で、JNDI名はデフォルトでは「lift」であると書いたが、このJNDI名を変えて接続してみたい。

設定は簡単で、

Boot.scalaの中のBootクラスの中のbootメソッドの一番最初に
[scala]class Boot {
  def boot {
DefaultConnectionIdentifier.jndiName = "custom"
…[/scala]
という記述を追加するだけ。

これで、customという名のJNDIを使ってデータベース接続を行うようになる

[Scala]Scala + Liftで、GlassFishの接続プールを使う

GlassFishはWeb ・EJBコンテナなので、せっかくなので、Scala + Liftの環境からJDBC接続プールを使いたい。

幸い、liftにはJNDIでDB接続する仕組みが入っているようです。

liftがデフォルトで参照するJDBC接続プールは、liftという名前のJNDIなので、今回はliftという名前で設定します。

GlassFishはほぼ標準状態で入っている前提で。

まずはmysqlのjdbcドライバをGlassFishのlibにコピーします。

http://www.mysql.com/downloads/connector/j/

からダウンロードして c:\glassfish3/lib コピーします。

GlassFishのドメインを起動します。
[shell]asadmin start-domain[/shell]
つぎに

http://localhost:4848/

にアクセスします。

ログイン画面が出たら、初期設定時の情報でログインします。

ここでログインがどうしても失敗する場合、server.logにおかしなエラーが出てたら、ドメインの再起動をすると直ったりします。この辺はよく分かりません。

ログインすると、

というメニューが出ます。

この中のリソース – JDBC – JDBC接続プールとたどります。

新規ボタンを押して

 

プール名:lift
リソースタイプ:javax.sql.ConnectionPoolDataSource
データベースドライバのベンダー:MySql
と設定する

ステップ2/2では、追加プロパティー以外は修正しなくても良いです。

追加プロパティで変更する箇所は

user [データベースユーザ名]
password [データベースパスワード]
DatabaseName MySQL
ServerName localhost
port 3306
URL jdbc:mysql://localhost:3306/test

です。

URLのtestは、使用するデータベース名になります。

接続プールの作成が完了したので、次にJDBCリソースを追加します。

こちらも、同様に新規ボタンで項目を作成します。

liftがデフォルトで認識するJNDI名がliftなので、今回はliftにします。

これで、接続プールの設定が完了しました。

あとはscala + Liftのプロジェクトをデプロイすると、接続プールを使ってMySQLにアクセスするようになります。

そのうち、JNDI名を変更したバージョンも実験してみたいと思います。

[Scala]Maven + Scala + LiftのプロジェクトをGlassFish上にデプロイしてeclipseでデバッグする

なんか長いタイトルですが

要はMavenで作ったScala + LiftのプロジェクトをGlassFishにデプロイしたい

で、eclipseでGlassFishにデプロイしつつデバッグもしたい

という欲張り企画なんですが

eclipseのプロジェクト作成とか、Mavenのプロジェクト作成では

これらの要件を満たす設定になってくれないので

手動で設定を変更します。

必要な物

eclipseの環境構築は
やっぱりScala and Liftな環境をEclipseで開発したい!
を参照

GlassFishのインストール

まずはJava EE 6 SDKをインストールします。

このインストールで、GlassFishが同時にインストールされるはずです。

普通にインストールすると、c:\glassfish3にインストールされるはずです。

このとき、インストーラをダブルクリックで起動するとエラーになる場合

[shell]C:\> java_ee_sdk-6u3-windows-ml.exe -j "%JAVA_HOME%"[/shell]

とすればインストーラを起動できます。

eclipseからGlassFishを参照するように設定

インストールが完了したら、eclipseからGlassFishが見えるように設定します。

Open PerspectiveからJava EEを選択。

すると、ビューの下にServersタブが現れるので、その中で右クリック。
New – Serverを選択

右上のDownload additional server adaptersをクリック

出てきた画面で、Oracle GlassFish Server Adapterを選択
インストールが終わると、画面が閉じるので、またServersタブの中でNew – Serverを選択
すると、GlassFishの選択肢が増えているので、GlassFish 3.1.1を選択

この辺はそのままで、Finishをクリック。
インストール時に設定をいじっていたら、その情報を登録

これで、サーバの登録が出来たので、eclipse上からGlassFishを操作することが出来ます。

プロジェクトの作成

まずはeclipseでプロジェクトの新規作成をします。

Scala and LiftのプロジェクトをEclipse上に作成する

上記の記事を参考にすると、とりあえずScala + Liftのデバッグが出来るプロジェクトが出来上がっているはずです。

続いて、プロジェクトのRun Asで実行できるようにRun on Serverを使えるようにします。
Run on Serverというのは、先ほどServerタブで設定したGlassFish上でプロジェクトを実行できるようになるコマンドです。

一度プロジェクトをeclipse上から削除し、.projectファイルを開きます。

<buildSpec>

[xml]
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>[/xml]

を追加

<natures>

[xml]<nature>org.eclipse.wst.common.project.facet.core.nature</nature>[/xml]

を追加

.settingsフォルダに

org.eclipse.wst.common.component ファイルを作成し
中身を以下のようにする
※deploy-nameはプロジェクト名を設定

[xml]<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="プロジェクト名">
<wb-resource deploy-path="/" source-path="/EarContent" tag="defaultRootSource"/>
</wb-module>
</project-modules>[/xml]

もう一つ、org.eclipse.wst.common.project.facet.core.xml ファイルを作成し
中身を以下のようにする

[xml]<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<runtime name="GlassFish 3.1.1"/>
<fixed facet="jst.ear"/>
<installed facet="jst.ear" version="6.0"/>
<installed facet="sun.facet" version="9"/>
</faceted-project>[/xml]

プロジェクトをインポート

これで、Run AsにRun on Server項目が追加されているはずです。

※これらの追加設定については、新規プロジェクト – Java EE – Enterprise Application Projectで作成したプロジェクトの設定を元にしています。
なので、バージョンが変わった場合、Enterprise Application Projectで作成したプロジェクトの設定をもとに設定を変更すれば良いはずです。

次に、GlassFishへデプロイする時のディレクトリ構成を設定します。

プロジェクトのプロパティを開いて、Deployment Assemblyを選択します。

Addボタンを押して、Folderを選択します。

src/main/resourcesとたどって、Finishを押します。

Deploy PathにはWEB-INF/classesを入力します。

同様にsrc/main/scalaも追加し、Deploy PathをWEB-INF/classesにします。

src/main/webappも同様に追加しますが、これのDeploy Pathは/のままにします。

libは、mavenから持ってくるのですが、めんどくさそうなので、ここはサボってしまいます。

プロジェクトディレクトリで

[shell]mvn package[/shell]

を実行

すると、targetディレクトリに

プロジェクト名-0.0.1-SNAPSHOT

という感じのディレクトリが出来るので、この中の

WEB-INF/libをフォルダでたどって追加します。

この項目のDeploy PathはWEB-INF/libを設定します。

一通り設定が完了したので、プロジェクトのRun Asから、Run on Serverを選んでみます。

出てきた画面で、そのままFinishを押すと、サーバが起動され、プロジェクトがデプロイされます。

あとは、ブラウザでlocalhost:8080に続いてプロジェクト名を入れる事で
画面にアクセス出来ます。
http://localhost:8080/ScalaLiftOnGlassFish

[Scala]PartialFunction 部分関数?

とりえあず、以下のようなコードを書きます。

[scala]val pf:PartialFunction[String,Option[String]] = {
case null => None
case "" => None
case s => Some(s)
}[/scala]

これで、nullはNone、””もNone、普通の文字列はOptionに変換という処理をしてくれます。

関数の使い方は

[scala]val list = List("test1", null, "test2", "", "test3", "staging1")
list collect pf[/scala]

とすると、

[scala]List(Some(test1), None, Some(test2), None, Some(test3), Some(staging1))[/scala]

が返ってきます。

また、リストから一部の項目をフィルタリングしたりする場合にも使えます。

[scala]val regStaging = """staging.+""".r
// この処理は、staging.+にマッチする文字のみを返す
// 正規表現マッチの場合はあらかじめ正規表現オブジェクトを作っておく必要がある
val staging: PartialFunction[String, String] = { case t @ regStaging() =&gt; t }[/scala]

こんな感じにした場合に

[scala]list.collect(staging)[/scala]

を実行すると、

[scala]List(staging1)[/scala]

が返ってきます。

このPartialFunctionが便利なところが、orElseでPartialFunction同士を結合することが出来ることです。

以下のようにtestAndStagingを作成します。

[scala]val regStaging2 = """(staging)(.+)""".r
val staging2: PartialFunction[String, String] = { case t @ regStaging2(a, b) => a + "の" + b }
list.collect(staging2) // => List(stagingの1)を返す

val regTest = """test.+""".r
// この処理はtest.+にマッチする文字のみ返す
// 正規表現マッチの場合はあらかじめ正規表現オブジェクトを作っておく必要がある
val test: PartialFunction[String, String] = { case t @ regTest() => t }
list.collect(test) // => List(test1, test2, test3)を返す

//test.+とstaging.+の両方にマッチする条件を構築
val testAndStaging = test.orElse(staging)
list.collect(testAndStaging)[/scala]

すると、

[scala]List(test1, test2, test3, staging1)を返す[/scala]

が返ってきます。

[Scala]可変長引数と : _*

Scalaで可変長引数を受け取る関数を定義する時は

[scala]def func(args: String*) = args.foreach(println)[/scala]

と書く

で、この関数に対して

[scala]func( "test1", "test2", "test3")[/scala]

とすれば、

[text]test1
test2
test3[/text]

となる

で、本題で、「: _*」ですが

この可変長引数を取る関数にリストを渡す時に使用します。

[scala]val list = List("test1", "test2", "test3")
func(list)[/scala]

では、

[text]<console>:35: error: type mismatch;
found   : List[/text]

[text]required: String func(list)[/text]

のようなエラーになりますが

[scala]func(list: _*)[/scala]

とすれば、正常に出力されます。

[Scala]LiftでMySQLに繋ぐ(sbt編)

前々回くらいで、【Scala】LiftでMySQLに繋ぐ(Maven編)では、MavenでMySQLにつなぐための設定をしたが、今回はsbtでMySQLにつなぐための設定を。

project/build/LiftProject.scalaファイルに、MySQLのドライバの設定を追加します。

[scala]override def libraryDependencies = Set(
"net.liftweb" %% "lift-webkit" % liftVersion.value.toString % "compile",
"net.liftweb" %% "lift-mapper" % liftVersion.value.toString % "compile",
"org.mortbay.jetty" % "jetty" % "6.1.26" % "test",
"junit" % "junit" % "4.7" % "test",
"ch.qos.logback" % "logback-classic" % "0.9.26",
"org.scala-tools.testing" %% "specs" % "1.6.9" % "test",
"com.h2database" % "h2" % "1.2.147",
"mysql" % "mysql-connector-java" % "5.1.14" % "runtime"// <= これ追加
)[/scala]

続いて

src/main/resources/props/default.props にデータベースの定義を追加する

[text]db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/lift_mysql_example
db.user=root
db.password=[/text]

MySQLにログインしてデータベースを作成

[shell]mysql> create database lift_mysql_example;[/shell]

jettyを起動
※Mavenが起動時に必要なライブラリを全部そろえてくれる

[shell]sbt ~jetty-run[/shell]

これで、mysql上にusersテーブルが作成されます。
※デフォルト状態のLiftプロジェクトの場合

[Scala]Liftのrunmodeについて

Liftにはrun modeが6つ準備されている

  • development
  • test
  • staging
  • production
  • pilot
  • profile

デフォルトでは、developmentが選択される。

run modeを変えて起動する場合、
-Drun.mode=production
というように、起動時にオプションを指定することで変えることが出来る

run modeでDBの接続する先を変えたりする場合

src/main/resources/propsにproduction.default.props(ファイル名の一例)というファイルを置く事で、このファイルに設定された内容で起動する。

[Scala]LiftでMySQLに繋ぐ(Maven編)

Scala + Liftの環境は、最初はH2DBにつながるようになっている。

一般的にサービスを提供する場合、やはりMySQLなどに繋いで使いたい

ということで、MySQLに接続する方法

Mavenでプロジェクトを作っている前提で

pom.xmlファイルのdependenciesに以下を追加

[xml]<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>[/xml]

続いて

src/main/resources/props/default.props にデータベースの定義を追加する

[text]db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/lift_mysql_example
db.user=root
db.password=[/text]

MySQLにログインしてデータベースを作成

[shell]mysql> create database lift_mysql_example;[/shell]

jettyを起動
※Mavenが起動時に必要なライブラリを全部そろえてくれる

[shell]mvn jetty:run[/shell]

これで、mysql上にusersテーブルが作成されます。
※デフォルト状態のLiftプロジェクトの場合

[Scala]Parallel Collections

2.9からParallel Collectionsが実装されてますが、よく分かりません。

foreach, map, filterなどの処理をする時にマルチコア対応したコレクションという事ですかね。
[scala]import scala.collection.parallel.mutable._[/scala]
しておく必要がありそうです。


[scala]Array(1, 2, 3, 4, 5).par.sum
// または
ParArray(1, 2, 3, 4, 5).sum[/scala]
並列処理出来るコアの数を取得する
[scala]scala.collection.parallel.availableProcessors[/scala]
普通のArrayを並列Arrayに変換するには
[scala]Array(1, 2, 3, 4, 5).par[/scala]
逆に並列Arrayを普通のArrayに戻すには
[scala]ParArray(1, 2, 3, 4, 5).seq[/scala]
ArrayとListは、普通のから並列へ変換する時に時間がかかるので、もしかしたら
直接ParArrayとかParListとか作った方が早いのかも。
Range、Vector、Map、Setはオーバーヘッドが無いようだ。

[Scala]foldLeft(/:)

/:」という物が何か知りたくて調べてたら、これは

foldLeftのエイリアスだと知った。

で、foldLeftというのは、何かというと、

Rubyでいうとinjectみたいなもの?

rubyのinject
[ruby][2, 3, 4, 5].inject(0) {|result, item| result + item}[/ruby]
と書くと、2 + 3 + 4 + 5 の結果が返ってくる

要は、0を初期値として、リストのアイテムごとにブロックで指定した処理をして、戻り値としてresultを返すという物だ

これをScalaで書くと
[scala]val list = List(2, 3, 4, 5)
list.foldLeft(0){(result, item) =&gt; result + item}[/scala]
となる

で、このfoldLeftのエイリアスとして「/:」があるのだが

/:」を使うと
[scala](0 /: list)(_+_)[/scala]
と書くことが出来る

ずいぶん暗号っぽくなってしまうが、これを読み解くと

/:の「:」というのはメソッド名の終端に「:」が付く物は右結合となり、右側から解釈されるので

/:というのはlistのインスタンスメソッドと言うことになる

そう考えると、foldLeft/:で置き換えた。というイメージがしやすいと思う。

あと、foldLeftという名前の通り、リストの左から処理を実行する。

逆に右から処理を実行させたい場合
[scala]list.foldRight(0){(result, item) =&gt; result + item}[/scala]
とかく、この場合のエイリアスは「:\

:\での書き方も若干変わって
[scala](list :\ 0)(_+_)[/scala]
となる。

[Scala]eclipseでMavenを使ってScalaのプロジェクトを作り、Specsでテストするようにする

まずはMavenでプロジェクトを作成する

scala-archetype-simple v1.3 を選択

あとは順次進んでプロジェクトを作成する

できあがったプロジェクトは一度eclipseから削除する
※間違えてもディスクから削除はしない

エディタなどで「.project」ファイルを開く

<natures>タグの中に以下を1行を追加

[xml]<nature>org.scala-ide.sdt.core.scalanature</nature>[/xml]

[xml]<name>org.eclipse.jdt.core.javabuilder</name>[/xml]

の行を以下のように書き換える

[xml]<name>org.scala-ide.sdt.core.scalabuilder</name>[/xml]

「.project」ファイルを保存する

eclipseで、プロジェクトをインポート

エラーがいくつか出ているので、これを解決していきます。

Plugin execution not covered by lifecycle configuration: org.scala-tools:maven-scala-plugin:2.15.0:compile (execution: default, phase: compile)

というエラーは、ダブルクリックするとpom.xmlファイルが開くので、overviewタブに切り替えて

をクリック、出てきたメニュー

でPermanently mark goal compili in pom.xml as ignored in ~なんていう所をクリックして
出てきたダイアログでOKすると、エラーが解決されます。

More than one scala library found in the build path, including at least one with an incompatible version. Please update the project build path so it contains only compatible scala libraries

というエラーは

このバージョンを使っているScalaのバージョンに変更する。
今回は2.9.1


Missing artifact org.scala-tools.testing:specs_2.9.1:jar:1.6.5

というエラーが出るので、pom.xmlファイルエディタの画面のDependenciesというタブをクリックしてspecs_${scala.version} : 1.6.5という項目を開いて、1.6.9に変更する。

これで、プロジェクト作成完了

[Scala]Date型をフォーマットして文字列にする

%tytは日付および時刻変換文字用の接頭辞

%<tm<は引数のインデックスを指定するインデックスで、以前の書式指示子の引数が再利用されます

つまり、

%$1tmと同じ意味になります。

$1というのは、引数のインデックスで

とすれば、%tmでは、d1の年を、%$3tmでは、d3の月を、%$2tdでは、d2の日を参照してフォーマットされる

[Scala]WindowsのJDK(32bit)をJDK(64bit)に入れ替えたときにエラーが出る

このようなエラーが出た場合、tempディレクトリにキャッシュのdllが残っているのが原因。

以下のコマンドで削除できる