Windowsでシンボリックリンクを作成

どうやらWindowsでもシンボリックリンクが作成できるようです。Vista以降。

というのもScalaのベータ版を使ってみたいがためいちいち入れ替えるのもあれなので、うまくできないかなと探していたところ以下の記事を発見

http://blog.livedoor.jp/s_imai_jp/archives/51360129.html

C:\Program Files (x86)>path
PATH=...;C:\Program Files (x86)\scala\\bin
;C:\play-2.1.3;C:\Program Files\Java\jdk1.7.0_40\bin;...
C:\Program Files (x86)>scala -version
Scala code runner version 2.10.2 -- Copyright 2002-2013, LAMP/EPFL
C:\Program Files (x86)>mklink /d scala scala-2.11.0-M4
scala <> scala-2.11.0-M4 のシンボリック リンクが作成されました
C:\Program Files (x86)>scala -version
Scala code runner version 2.11.0-M4 -- Copyright 2002-2013, LAMP/EPFL

Javaで自ホストのIPアドレスで127.0.0.1以外を取得する

ちょっと困ったのでメモ

通常JavaのInetAddress.getLocalHost().getHostAddress()から取得できるIPアドレスは127.0.0.1

これではちょっと使えません

ネットワークインターフェースを調べるとちゃんとした?IPアドレスが取得できます

import java.net.*;
import java.util.*;


public class test{
	public static void main(String[] argv)throws Exception{
		Enumeration n = NetworkInterface.getNetworkInterfaces();
			while (n.hasMoreElements()){
				NetworkInterface e = n.nextElement();
				Enumeration a = e.getInetAddresses();
				while ( a.hasMoreElements()){
					InetAddress addr = a.nextElement();
																		if (!addr.getHostAddress().equals("127.0.0.1"))
							 System.out.println(addr.getHostAddress());
				}
		 }
	}
}

javascriptでサブドメインの異なるサイトでクッキーの共有

こちらの記事を参考にJavascriptでサブドメインの異なるサイト間でクッキーの恭有してみました。

http://d.hatena.ne.jp/dirablue/20090506/1241607961

http://www1.example.com/setCookie.html

  • setCookie.html

  





http://www2.example.com/getCookie.html

  • getCookie.html

  



ポイントはHTMLを設置するパスを同じにすることとdomain指定の前にドットをつけることでしょうか?

あとIDやパスワードをクッキーに保存してはいけません^^);

eclipse+tomcatでアクセスログの場所

意外とわからなかったのでメモ。

環境

  • eclipse kelpher
  • tomcat 7
  • java 7

手順

  1. プロジェクトの作成でWebーDynamicWebで作成
  2. Eclipseの環境設定のServer、RuntimeEnvironmentsにtomcat 追加
  3. プロジェクトのpropertiesからjava build pathのLibrariesにadd LibrariesからServer Runtime のTOMCATを追加
  4. なんか作成
  5. Debug AsのDebug ConfigurationからTomcatのargumentsを確認
  6. ここの-Dcatalina.baseのパス以下にTOMCATのいろいろなものが入っている(/Users/username/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0)
  7. このlogs以下にアクセスログが作成される

PlayFramework2.1でセッションタイムアウトを作ってみた

PlayFrameworkのセッションはCookieになります。ブラウザを閉じるまで有効なので、従来のservletなどで実現してきたsessionの観念はありません。

これが意外と困ってしまうので(タイムアウトした際にログアウトさせるなど)Cookieに時間を持たせることによりにたようなものを実装してみました

routes

GET		 /													 controllers.Application.index
GET		 /login													controllers.Application.login
POST		/login													controllers.Application.submit

controllers.Application.scala

package controllers

import play.api._
import play.api.mvc._
import helper.Session
import helper.Login
import play.api.data._
import play.api.data.Forms._
import play.api.data.validation.Constraints._
	
case class User(id:String,password:String)
	
object Application extends Controller {
	val userForm = Form[User](
			mapping(
					"id" ->nonEmptyText,
					"password"->text(minLength=6))
			((id,password)=>User(id,password))((user:User)=>Some(user.id,user.password))
	)
	
	def index = Action {request=>{
			if(Session.check(request))Ok(views.html.index("LoginOK"))
			else Redirect(routes.Application.login)
		}	 
	}
	def login=Action{
		Ok(views.html.login(userForm))
	}
	def submit = Action { implicit request =>
		userForm.bindFromRequest.fold(
			errors => BadRequest(views.html.login(errors)),
			user => {
				if(Login.check(request,user.id,user.password))Redirect(routes.Application.index).withSession(Session.set(request))
				else BadRequest(views.html.login(userForm))
			}
		) 
	}
}

helper.Login.scala

本来ならばログインIDとパスワードとつきあわせてチェックするのですがとりあえず必ずOKになるように

package helper

import play.api._
import play.api.mvc._
object Login {

	def check(req:Request[AnyContent],id:String,password:String):Boolean={
		true // NO check
	}
}

helper.Session.scala

クッキーに保存した時刻と現在時刻を比較し、ログアウトの判定

package helper

import play.api._
import play.api.mvc._
object Session {
	val MAX_MILLISEC:Long=1000*60	// time out 
	val SESSION_KEY="play2"
	
	def check(req:Request[AnyContent]):Boolean={
		req.session.get(SESSION_KEY).map{
			user=>{ 
				val cookieDate=user.toLong
				val nowDate=new java.util.Date().getTime();
				if(nowDate-cookieDatenew java.util.Date().getTime().toString())
	}
// ログアウトボタンを押したらこれを呼ぶ、未実装
	def del(req:Request[AnyContent])={
		req.session - SESSION_KEY
	}
}

views.index.scala.html

@(message: String)
@message

views.login.scala.html

@(userForm:Form[User])

@import helper._

@helper.form(action=routes.Application.submit){
						@inputText(
								userForm("id"), 
								'_label -> "Username", 
								'_help -> "Please choose a valid username.",
								'_error -> userForm.globalError
						)
						
						
						@inputPassword(
								userForm("password"), 
								'_label -> "Password",
								'_help -> "A password must be at least 6 characters. "
						)
						



}

ログイン後1分放置するとログイン画面に戻ります

Slick+PlayFramework2.1でDBアクセスしjsonで出力

実際の業務では、サンプルなどでよく見かける、データの作成、更新、参照、削除という流れは実際ではあまりなく、既にあるデータを参照するだけとか祖いうのが多いかと思います。

前回までで、既存データベースに入っているデータを取得することができたので、JSON形式で出力してみます。

GSON

sjsonやPlay標準のJSONなど何種類かあるようですが、ちょっと試したところうまくいかなかったので、GSONを使用することにしました。

あらかじめGSONをダウンロードしておきeclipseのパスに追加しておきます。

http://code.google.com/p/google-gson/

mysql

use data
;
create table price(
code varchar(10) not null,
date datetime not null,
open int ,
high int,
low int,
close int
)
;
create unique index price1 on price(code,date)
;

application.conf

db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/data"
db.default.user=root
db.default.password=
slick.default="models.*"
evolutionplugin=disabled

routes

GET /data/price/:code	controllers.Data.OHLC(code:String)

controllers.Data.scala

package controllers
import play.api._
import play.api.mvc._
import models._
import com.google.gson._

object Data extends Controller {
	val gson:Gson=new GsonBuilder().setDateFormat("yyyy-MM-dd").create // 日付のフォーマットをしておく
	def OHLC(code:String)=Action {
		Ok(views.html.json(gson.toJson(Prices.select(code))))
	}
}

models.Price.scala

package models
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import play.api.db._
import play.api.Play._

import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import Q.interpolation

case class Price(code:String,date:java.sql.Date,open:Int,high:Int,low:Int,close:Int) extends Ordered[Price]{
	def compare(that:Price):Int={
		date.getTime().compare(that.date.getTime())
	}
}

object Prices extends Table[Price]("price") {
	val DATE_TERM=180 // 180日分とる
	
	def code=column[String]("code",O.PrimaryKey)
	def date=column[java.sql.Date]("date",O.PrimaryKey)
	def open=column[Int]("open")
	def high=column[Int]("high")
	def low=column[Int]("low")
	def close=column[Int]("close")
	def * = code ~ date ~ open ~ high ~ low ~ close <> (Price,Price.unapply _)

	implicit val getPrice=GetResult(rs=>Price(rs<<,rs<<,rs<<,rs<<,rs<<,rs<<))
	
	def select(code:String)= connectDB{
		val list=sql"select * from price where code=$code order by date desc limit $DATE_TERM".as[PriceHistAdj].list.sorted
		// sort 逆順なので並べ替える、GSON用にArrayList化
		val ary=new java.util.ArrayList[Price]
		for(l<-list)ary.add(l)
		ary
	}
	def connectDB[Any](f: => Any): Any = {
		Database.forDataSource(DB.getDataSource("data")) withSession {
			f
		}
	}
}

views.json.scala.html

jsonp用

@(json:String)
callback(@json);

Slick+PlayFramework2.1でDBアクセス#2

既存のデータベースにアクセスしてみます。

DBのコネクションをPlayFrameworkから与えることでモデル側でコネクションを作成しません

MySQL

create table OHLC(
code varchar(10) not null,
date datetime not null,
open int null,
high int null,
low int null,
close int null,
unique key OHLC1(code,date) 
)

application.conf

db.default.driver=org.gjt.mm.mysql.Driver
db.default.url="jdbc:mysql://localhost/live?useOldAliasMetadataBehavior=true" 
db.default.user=root
db.default.password="" 
slick.default="models.*"
evolutionplugin=disabled

routes

GET /:code controllers.Application.price(code:String)

controllers.Application.scala

package controllers

import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import models._

object Application extends Controller {
	def price(code:String) = Action{
		Ok(views.html.index(Price.select(code)))
	}
}

models.Price.scala

package models
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import play.api.db._
import play.api.Play._

import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import Q.interpolation


case class Price(code:String,date:java.sql.Date,open:Int,high:Int,low:Int,close:Int)

object Prices extends Table[Price]("OHLC"){
	def scode=column[String]("code",O.PrimaryKey)
	def date=column[java.sql.Date]("date",O.PrimaryKey)
	def open=column[Int]("open")
	def high=column[Int]("high")
	def low=column[Int]("low")
	def close=column[Int]("close")

	def * = code ~ date ~ open ~ high ~ low ~ close <> (Price,Price.unapply _)

	implicit val getPrice=GetResult(rs=>Price(rs.nextString,rs.nextDate,rs.nextInt,rs.nextInt,rs.nextInt,rs.nextInt))
	
	def price(code:String):List[Price]= connectDB{
		sql"select * from OHLC where code=$code".as[Price].list
	}
	
	def connectDB[Any](f: => Any): Any = {
		Database.forDataSource(DB.getDataSource("default")) withSession {
			f
		}
	}
}

views.index.scala.html

@(prices: List[Price])
				@prices.map { price =>
						@price.code,
						@price.date
						@price.open
}

Slick+PlayFramework2でデータベースアクセス

ScalaでPlayFrameworkを使う場合にDBアクセスにはanormとslickがあるようです。

slickはscalaQueryと呼ばれていたものが進化した模様。

scala2.9まではscalaQuery,それ以降はslickらしいです

http://d.hatena.ne.jp/tototoshi/20121204/1354615421

Build.scalaに必要なモジュールを書いてインストールするのが一般的らしいですが、うまくいかなかったので手動インストールで作成してみます。

slick

https://github.com/freekh/play-slick

からZIPでダウンロードし解凍

 $ cd slick-1.0.1
 $ sbt
 > compile
 > package
 $ find .|grep jar
	./slick-testkit/target/scala-2.10/slick-testkit_2.10-1.0.1.jar
	./target/root/scala-2.10/root_2.10-1.0.1.jar
	./target/scala-2.10/slick_2.10-1.0.1.jar

play-slick

プラグインなのでこちらも入れます

https://github.com/freekh/play-slick

 $ cd play-slick-master
 $ sbt
 > compile
 > package
 $ find .|grep jar
 ./target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar

プロジェクト作成

$ play new sample
			 _						_
 _ __ | | __ _ _	_| |
| '_ \| |/ _' | || |_|
|	__/|_|\____|\__ (_)
|_|						|__/

play! 2.1.2 (using Java 1.7.0_25 and Scala 2.10.0), http://www.playframework.org

The new application will be created in /Users/admin/Documents/workspace/play_sample/sample

What is the application name? [sample]
> sample

Which template do you want to use for this new application? 

	1						 - Create a simple Scala application
	2						 - Create a simple Java application

> 1
OK, application sample is created.

Have fun!

$ cd sample
$ play eclipse
$ mkdir lib
$ cp slick-1.0.1/target/scala-2.10/slick_2.10-1.0.1.jar .
$ cp play-slick-master/target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar .

Eclipse

  • eclipseの既存プロジェクトの読み込みで読み込む
  • プロジェクトのプロパティからslick_2.10-1.0.1.jar、play-slick_2.10-0.3.3-SNAPSHOT.jarのライブラリを追加

PlayFramework

http://takashima0411.hatenablog.com/entry/2012/11/28/231817

こちらの方のサンプルをそのままいただきました

Application.scala
package controllers

import play.api._
import play.api.mvc._

import play.api.data._
import play.api.data.Forms._

import models._

object Application extends Controller {

	val taskForm = Form(
		"label" -> nonEmptyText)

	def index = Action {
		Redirect(routes.Application.tasks)
	}

	def tasks = Action {
		Ok(views.html.index(Tasks.all(), taskForm))
	}

	def newTask = Action { implicit request =>
		taskForm.bindFromRequest.fold(
			errors => BadRequest(views.html.index(Tasks.all(), errors)),
			label => {
				Tasks.create(label)
				Redirect(routes.Application.tasks)
			})
	}

	def deleteTask(id: Long) = Action {
		Tasks.delete(id)
		Redirect(routes.Application.tasks)
	}

}
Task.scala
package models

import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

case class Task(id: Long, label: String)

object Tasks extends Table[Task]("TASK") {

	def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
	def label = column[String]("LABEL", O.NotNull)
	def * = id ~ label <> (Task, Task.unapply _)
	def ins = label returning id

	def all(): List[Task] = connectDB {
		Query(Tasks).sortBy(_.id).list
	}

	def create(label: String) = connectDB {
		Tasks.ins.insert(label)
	}

	def delete(id: Long) = connectDB {
		Tasks.where(_.id === id).delete
	}

	def connectDB[Any](f: => Any): Any = {
		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {
			f
		}
	}

}
Global.scala
import play.api._
import models._
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import models._
import java.sql.{Date,Time,Timestamp}

object Global extends GlobalSettings {

	override def onStart(app: Application) {
		Logger.info("Application has started")

		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {

			Tasks.ddl.create

		}

	}

	override def onStop(app: Application) {
		Logger.info("Application shutdown...")
	}

}
index.scala.html

@(tasks: List[Task], taskForm: Form[String])

@import helper._


		
		

@tasks.size task(s)

    @tasks.map { task =>
  • @task.label @form(routes.Application.deleteTask(task.id)) { }
  • }

Add a new task

@form(routes.Application.newTask) { @inputText(taskForm("label")) }
routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET		 /													 controllers.Application.index
GET		 /index											controllers.Application.index
GET		 /tasks											controllers.Application.tasks
GET		 /newTask										controllers.Application.newTask
GET		 /deleteTask/:id								 controllers.Application.deleteTask(id:Long)

# Map static resources from the /public folder to the /assets URL path
GET		 /assets/*file							 controllers.Assets.at(path="/public", file)
application.conf
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"


slick.default="models.*"

# Evolutions
# ~~~~~
# You can disable evolutions if needed
evolutionplugin=disabled

これでとりあえず動きます