Scala+DBMS+Web スカラ座の夜

2016年5月28日

Scala2.11への取り組み

Filed under: Scala — admin @ 11:46 PM

このページをとても長い間書き込みをしないでいました。
Scalaを仕事で使い続けていますが、フレームワークの更新は必要に迫られてかなり行ってきました。
自分でしか使っていないので公開していませんでしたが、試したり、調べたりしていることを書きます。

自作しているScalaのフレームワークは、2種あります。
ひとつは、HTML系のフレームワーク。もうひとつは、DBMS系のフレームワークです。

HTML系は拡張していなかったのですが、なかなかアイデアを形にできずそのままになっています。
今回、新しいScala2.11に対応しようとしています。HTMLパーサもHTML5への対応を入れました。これは必須ですね。

DBMS系は、開発環境がOracleとMySQLだけだったのですが、HEROKUではPostgresqlを使い、
AzureではSQL serverを使っているのでこの2つのDBMSでも使えるように拡張しました。
そのおかげで、1つのソースコードで書いたプログラムがいろいろなDBで動くので助かっています。

ということで、Scalaを愛するひとりとして。

2013年1月3日

タグ置換 その4 タグを表示させないようにする。

Filed under: Scala — admin @ 2:49 AM

タグを表示させないようにするです。

これには、seedodisable属性を使います。
条件によってWEBデザイナが作ったタグを表示させないようにします。

hello2.htmlファイルに以下のテスト用のタグを追加します。

以下の例では、seedodisable属性の値が、”myapp.HelloWorld:disabled:1″となっています。
HelloWorldクラスのdisabled関数は、引数にInt型を渡すことができ、上記例では1となります。

これは、seedodisable属性に限らず、seedo属性やseedorep属性の値も関数に引数を1つ渡すことができます。


TEST3
xxxxxxxxxxtruexxxxxxxxxxx

TEST4
xxxxxxxxxxfalsexxxxxxxxxxx

TEST5
xxxxxxxxxxfalsexxxxxxxxxxx

TEST6
xxxxxxxxxxxtruexxxxxxxxxx



before2




HelloWorldクラスにも真偽を返すBoolean型の関数を追加します。
確かに、disabled関数は、Int型の引数を受け取っています。
0を引数に渡せばfalseの偽が返されます。0以外の値が引数に渡されれば真のtrueが返されます。

  def disabledTrue : Boolean = {
    println("####### HelloWorld disabledTrue")
    true
  }
  def disabledFalse : Boolean = {
    println("####### HelloWorld disabledFalse")
    false
  }
  def disabled(t:Int) : Boolean = {
    println("####### HelloWorld disabled "+t)
    if(t == 0)
      return false
    true
  }



実行すると以下のようにタグが置換されます。
trueを返す関数が実行されるとそのタグで囲われている部分すべてを表示しません。



TEST3
TEST4
xxxxxxxxxxfalsexxxxxxxxxxx

TEST5
xxxxxxxxxxfalsexxxxxxxxxxx

TEST6



after2




seedodisable属性を定義した内側に、先ほどのseedorep属性のタグを定義することもできます。
以下の例では、DIVタグのseedodisable属性をかぶせています。



TEST7
A1 A2 A3 A4
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4

before3

実行すると以下のようにseedodisable属性によって表示されなくなります。


TEST3
TEST4
xxxxxxxxxxfalsexxxxxxxxxxx

TEST5
xxxxxxxxxxfalsexxxxxxxxxxx

TEST6
TEST7

after3

タグ置換 その3 繰り返して置換する

Filed under: Scala — admin @ 12:53 AM

前回、seedorep属性について説明しました。

次に、繰り返しによる置換の機能をお見せします。
この機能は、2つの属性をseedorep属性があるタグの内側に記述します。
seedorecord属性 と seedofield属性 です。

住所録や商品一覧は、レコードによって住所や商品を格納し、複数のレコードで一覧を構成します。
これをtableタグで一覧にするとき、テーブルのTDタグによって囲まれた値を置換する手順を提供します。

tableタグのseedorep属性によって、seedorecordTest関数を定義します。
1件すなわち1レコードの単位をtrタグにseedorecord属性を定義します。
以下の例では、HD、a、b、cの4つのレコードが定義されます。


tdタグには、レコードの項目を定義するために、seedofield属性を入れます。
seedorecord属性のbとcには、a1,a2,a3,a4 を定義します。
HDのようにseedofield属性を定義しなくてもいいです。


A1 A2 A3 A4
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4



before



ScalaのHelloWorldクラスに次のseedorecordTest関数を追加します。

	def seedorecordTest: String = {
		println("####### seedorecordTest " + tag)
		if (parameterMap != null) {
			println("map=" + parameterMap.size)
			parameterMap.foreach(i => { println(i._1 + "=" + i._2.toList) })
		}
		//    println("tag=["+tag+"]")
		var rec = ""
		if (record != null) {
			// seedoreocrd属性のレコード解析結果を表示する
			println("=============================================")
			for ((k, v) <- record) {
				println("<" + k + ">=")
				v.foreach { kv =>
					val (k1, v1) = kv
					println("[" + k1 + "]=[" + v1 + "]")
					rec += v1
				}
				println("-----------------------------------------")
			}

			rec += "\n\n" // 区切り

			for ((k, v) <- record) {
				if (k == "b") {
					val b = record.get("b").get
					b.put("a1", "Z11111")
					b.put("a2", "Z22222")
					b.put("a3", "Z33333")
					b.foreach { kv =>
						val (k1, v1) = kv
						rec += v1
					}
					b.put("a1", "AAA11111")
					b.put("a2", "BBB22222")
					b.put("a3", "CCC33333")
					b.foreach { kv =>
						val (k1, v1) = kv
						rec += v1
					}
				} else if (k == "c") {
				} else {
					v.foreach { kv =>
						val (k1, v1) = kv
						rec += v1
					}
				}
			}
		}
		"HelloWorld seedorecordTest [" + record.size + "] \n" + rec + "\n date=" + new Date
	}


seedorecord属性がbのレコードの値を使って、tdタグの値を置換します。
seedorecord属性によって処理されるタグ達は、LinkedHashMapクラスによって保持されます。

record:LinkedHashMap[String,LinkedHashMap[String,String]]

tdタグの間の文字列は、seedofield属性の値でHashMapにキー管理されますから、put関数で上書きすることができます。
LinkedHashMapはHashMapに追加した順序を保持しますからForループで取り出される順序は元のタグと同じとなります。



cのレコードは表示しないようにします。
それ以外のタグは、置換せずにそのまま表示することになります。

上記のHTMLソースを実行するとseedorecordTest関数が実行され、以下のようにタグが置換されます。



HelloWorld seedorecordTest [10] 
A1 A2 A3 A4
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4
A1 A2 A3 A4
A1 A2 A3 A4
Z11111 Z22222 Z33333 B4
AAA11111 BBB22222 CCC33333 B4
date=Thu Jan 03 01:49:24 JST 2013

after

いかがでしょう。使ってみたくなりましたか。

2013年1月2日

タグ置換とは その2 置換するメカニズム

Filed under: Scala — admin @ 10:13 PM

SeeDoフレームワークでは、HTMLタグを置換することがすべてと説明しました。


タグにseedo属性を追加すればその値に記述されたクラスメソッドを動的に実行し、関数の返り値で置換文字列を返します。
seedo属性は、開始タグと終了タグの間の文字列を置換しますが、タグごと置換したい場合もあります。
これには、seedorep属性を使うことができます。

「今日は2012/1/2です。」

 

タグがなくなります。

「今日は2012/1/2です。」

置換前のタグをプログラム側で入手することができる。

package myapp
import java.util.Date
class HelloWorld extends TmpApp {
  def today : String = {"「今日は"+new Date + "です。」"}
}

HelloWorldクラスは、TmpAppクラスをエクステントしている。
このクラスのメンバーの tag変数に置換元のタグが格納される。

上記例の場合は、tag変数の値は、

<div>「今日は2012/1/2です。」</div>

となります。

package myapp
import java.util.{Date,ArrayList,HashMap}
import scala.collection.mutable.LinkedHashMap
import ews.servlet.session._
import javax.servlet.http.HttpServletRequest
import ews.servlet.RedirectInfo

trait TmpApp {
  var tag:String = null	// Replaced original tag	// 置換元のタグ
  var record:LinkedHashMap[String,LinkedHashMap[String,String]] = null	// seedorecord属性があるとここに元タグ情報が保持される
  var parameterMap:HashMap[String,Array[String]] = null	// Parameter from request of servlet
  var session:Session = null	// セッション
  var request:org.apache.catalina.connector.RequestFacade = null	// Servletリクエスト
  var response:org.apache.catalina.connector.ResponseFacade = null	// Servletレスポンス
  var redirectUrl : String = null			// リダイレクト先のURL
  var redirectInfo : RedirectInfo = null	// フルパスでリダイレクト
}

 

それ以外にも、Servletのセッション(session変数)、リクエスト(request変数)、レスポンス(response変数)、リクエストで渡されたパラメータ(parameterMap変数)。
これらの情報を得ることができます。
さらに、りダイレクせたい場合は、redirectUrl 変数にレスポンス先のURLをセットしてリダイレクトさせることで任意のURLの画面遷移することが可能です。

タグ置換とは WEBデザインとWEBプログラムの分離

Filed under: Scala — admin @ 2:20 AM

HTMLタグを置換するとは以下の例で説明しましょう。

WEBデザイナが、ページに今日の日付を表示させるようにデザインします。

「今日は2013/1/2です。」

HTMLソースには以下のようにタグを記述します。

「今日は2013/1/2です。」

これをその日の日付を表示させるために、JAVAプログラマがJSPでコードを書くとこんな風になります。

"「今日は<%= new java.util.Date() %>です。」



JSPですから、HTMLソースのなかにJAVAソースコードが混在します。


SeeDoフレームワークでは、以下のように書きます。

「今日は2013/1/2です。」



<h1>タグに、seedoという属性を追加します。seedo属性の値は、”myapp.HelloWorld:today” と書きます。



この意味は、mayappパッケージにある、HelloWorldクラスのtodayメソッドを呼び出せです。

このtodayメソッドは、String型の値を返し、<h1>と</h1>タグに囲われた「今日は2013/1/2です。」を置換します。

Scalaプログラムは、

package myapp
import java.util.Date
class HelloWorld extends TmpApp {
  def today : String = {"「今日は"+new Date + "です。」"}
}



ページをアクセスした日が1月31日なら、以下のように動的生成されます。


「今日は2013/1/31です。」




ページでは、以下のように表示されます。

「今日は2013/1/31です。」



2013年1月 Scalaフレームワーク

Filed under: Scala — admin @ 1:49 AM

1年ほどこのページを更新しておりませんでしたが2013年1月再開です。

この1年は、フレームを実用システムに適用しておりました。実際のプロジェクトでSEEDOフレームをいろいろな人に使ってもらいました。

そのフィードバックを今年は紹介します。

「SEEDOフレームとは何か?」

このフレームワークを作るきっかけは、WEBデザイナとWEBプログラマの役割を完全に分離したいと感じたからです。

現在の商用WEBページの多くは、WEBコンサルティング会社とWEBデザイン会社とWEBシステム構築会社の分業によって構築されています。WEBコンサルティング会社とWEBデザイン会社が同じ企業であることもありますが、社内では分業されています。

WEBページを提供する企業は訪れてくる人に情報を発信し、モノやサービスを購入を促します。企業の要求を受けWEB系企業は利用者からみた印象と使い勝手とを企業からの要求とマッチするように努力します。

この手順は、以下のように流れます。


企業の要件 → コンセプト構築 → ワイヤーフレーム → WEBデザイン → WEBシステム

私がこの流れのなかで関与するのは、WEBシステムのプロセスです。

上流で時間を使われることが多く、システム化の作業は突貫作業となりがちです。この作業の効率化と品質の確保をどうするか?

PHPやRubyのようなスクリプト言語はひとつの回答ですが、ウォータフォールでしかないです。

SeeDoフレームのルールは、

1.HTMLに新しいタグは作らない。

2.開発言語の記述をHTMLに持ち込まない。



すでにJavascriptのコードがあり、jQueryがこれに加わると、これ以上他の言語を含ませたくない。新しいことを覚える努力は最小限にしたい。

では、どうやって動的コードをどうやって表現するか?

この回答は、「置換」です。WEBデザイナーがデザインした動的表現部分を、例えば、今の日付で置き換えたり、データベースからSELECTしたデータで置き換える。

この命題は、逆に「プログラム側にHTMLのタグを書かない」と、したい訳です。プログラムの中にタグを書いた途端、デザインに依存する。





HTMLデザインもコードもひとりで書いているから、面倒だとか、そんなの理想だよ。必要性を感じないひとはここでおしまい。

2012年2月20日

動的ページのフレームワークの機能拡張

Filed under: Framework,Scala — admin @ 8:01 PM

久しぶりにパーサー部分に機能追加

いままでの動的動作は毎回クラスからオブジェクトをNEWして関数実行していました。
これを、NEWしたオブジェクトに対して関数を複数実行できるように機能拡張。

タグ属性にseedoを定義して、以下のように値を設定する。

クラス名:関数名:引数
クラス名:関数名

<div align="center"  class="xxx" seedo="myapp.HelloWorldTop1:tb:2500" id="asse111" />

スタートタグとエンドタグの間の値を関数実行した返り値と置換します。

一度、指定したクラス名はページが有効である間はオブジェクトが保持されているので、
クラス名が同じで別の関数を設定すれば、NEWしたオブジェクトの関数を実行することができます。

<!doctype html>
<HTML>
<HEAD>
<title>Home</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</HEAD>
<BODY>
<h2>Hello world top</h2>
The current time is
<div class="seedo:myapp.HelloWorldDb1:tb">xxxxx</div>
<HR>
<div align="center" class="seedo:myapp.HelloWorldDb1:tb" />
<HR>
<div align="center"  class="xxx" seedo="myapp.HelloWorldTop1:tb:2500" id="asse111" />
<HR>
<table border="1">
<tr>
<th class="xxx" seedo="myapp.HelloWorldTop1:get:2" />
<td seedo="myapp.HelloWorldTop1:getName" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getDept" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getSal" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getJob">job</td>
</tr>
<tr>
<th class="xxx" seedo="myapp.HelloWorldTop1:get:3" />
<td seedo="myapp.HelloWorldTop1:getName" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getDept" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getSal" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getJob">job</td>
</tr>
<tr>
<th class="xxx" seedo="myapp.HelloWorldTop1:get:1" />
<td seedo="myapp.HelloWorldTop1:getName" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getDept" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getSal" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getJob">job</td>
</tr>
<tr>
<th class="xxx" seedo="myapp.HelloWorldTop1:get:0" />
<td seedo="myapp.HelloWorldTop1:getName" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getDept" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getSal" />
<td class="xxx" seedo="myapp.HelloWorldTop1:getJob">job</td>
</tr>
</table>
<HR>
</BODY>
</HTML>

このHTMLをフレームワークで実行すると、

HTMLファイルのなかで使っているHelloWorldTop1 クラスの定義は以下のとおり。

package myapp
import java.util.{HashMap,Date}
import scala.collection.JavaConversions._
import scala.collection.immutable._
import scala.xml._
import seedo.database._

class HelloWorldTop1 extends TmpApp {
  var EMPNO:String = "EMPNO"
  var ENAME:String = "ENAME"
  var SAL:String = "SAL"
  var DEPTNO:String = "DEPTNO"
  var JOB:String = "JOB"
  var MGR:String = "MGR"

  var records:Array[Array[Any]] = null
  def rc(record:Array[Any]) : Unit ={
    EMPNO = if(record(0)!=null){record(0).toString}else{""}
    ENAME = if(record(1)!=null){record(1).toString}else{""}
    SAL = if(record(2)!=null){record(2).toString}else{""}
    DEPTNO = if(record(3)!=null){record(3).toString}else{""}
    JOB = if(record(4)!=null){record(4).toString}else{""}
    MGR = if(record(5)!=null){record(5).toString}else{""}
  }
  def recx(record:Array[Any]) :Node =  {
	var nodes  = Queue.empty[Node]
	record.foreach{(fx) => nodes += <TD>{fx}</TD>}
    return <TR>{nodes}</TR>
  }  
  // Function one argument
  def tb(sal:String) : String = {
    tb(sal.toInt)
  }
  def tb(sal:Int) : String = {
    val deptno = parameterMap.get("deptno") match {
      case v:Array[String] => v(0).toInt 
      case null => 10
    }
    var sql:Db = null 
    try {
		sql = new Db
		sql.select("EMPNO,ENAME,SAL,DEPTNO,JOB,MGR")
			.from("EMP")
			.where("SAL > ?",sal)
			.or("DEPTNO = ?",deptno)
			.orderBy("EMPNO")
		records = sql.executeQuery
		var nodes  = Queue.empty[Node]
		records.foreach{(rec) => {
			nodes += recx(rec)
			rc(rec) // record values 最後のレコードの値が残ることになる。
		  }
		}
		val xml = <table border="2">{nodes}</table>
	    return "HelloWorldDb3 " + new Date + xml.toString
	} catch {
      case e:Exception =>{
        throw e
      }
    } finally {
    	if(sql != null)sql.close
    }
  }
  def get(no:Int) : String = {
    if(records != null && no < records.length) {
    	rc(records(no))
    	return "G E T "+no
    } else {
    	return "Empty"
    }
  }
  def getId : String ={EMPNO}
  def getName : String ={ENAME}
  def getDept : String ={DEPTNO}
  def getJob : String ={JOB}
  def getSal : String ={SAL}
  def getMgr : String ={MGR}
}

フレームワークのコードは以下のとおり。

package ews.servlet.sp

import java.util.HashMap
import org.xml.sax._
import org.xml.sax.helpers.DefaultHandler
import scala.collection.JavaConversions._
import scala.collection.mutable.Stack
import ews.servlet.session._

/**
 * HTMLを直接PrintWriterへ出力する。
 */
class ParserCallback6(pMap:HashMap[String,Array[String]], out:java.io.PrintWriter, session : Session) extends DefaultHandler {
	var buf = new StringBuffer
	val stackChange = new Stack[ExecTag]	// For substitution
	var locator:Locator = null
	var createClasses = new HashMap[String,ExecClass]	// created class
	override def toString : String = buf.toString
	override def setDocumentLocator (locator:Locator) :Unit=  {
		this.locator = locator
	}
	override def startDocument ():Unit= {}
	override def endDocument():Unit= {}
	// タグスタート
	override def startElement ( uri:String,  name:String, qualifiedName:String , attrs:Attributes ):Unit={
		var tag = "<"
		if(name.startsWith("!")){
			tag += name
		} else {
			tag += name.toLowerCase	// tagを小文字で統一する
		}
		var fullFag = false	//
		var seedoFag = false // Page class object
		var end = false		// タグが / で閉じているか?
		for (idx <- 0 to attrs.getLength - 1){
			val attributeType = attrs.getType(idx)
			val attrLocalName = attrs.getLocalName(idx) 
		  	val attrName = attrs.getQName(idx)
			val attrValue = attrs.getValue(idx)
			if(attrLocalName.length > 0 && !"#text".equals(attrLocalName)){
				if("/".equals(attrLocalName) && attrValue.length == 0){
					end = true	// tagが閉じた
				} else if("!DOCTYPE".equalsIgnoreCase(name) && "html".equalsIgnoreCase(attrLocalName)){
					tag += " html"
				} else {
					if("class".equals(attrName) && attrValue.startsWith("seedo:")){
						val execCommand = attrValue.split(":")	// Each element is separated. 
						if(execCommand.length >= 3) {	// It doesn't substitute it if there are neither a class name nor a function name. 
							stackChange.push(new ExecTag(
							0
							,name
							,execCommand
							,new StringBuffer	// The tag to be substituted is maintained. 
							,false // class="seedo:...."
							))
							fullFag = true	// 動的タグとして置換状態にある
						} else {
							println("$$$$$$$$$$ execClass Warning " + attrName + "='" + attrValue + "'")
						}
					} else if("seedo".equals(attrName) && attrValue.length > 0){	// Servlet class
						val execCommand = attrValue.split(":")	// Each element is separated. 
						if(execCommand.length >= 1) {	// It doesn't substitute it if there are neither a class name nor a function name. 
							stackChange.push(new ExecTag(
							0
							,name
							,execCommand
							,new StringBuffer	// The tag to be substituted is maintained.
							,true // SEEDO attribute
							))
							seedoFag = true
						} else {
							println("$$$$$$$$$$ execClass Warning " + attrName + "='" + attrValue + "'")
						}
					} else {
						tag += (" " + attrLocalName)
						if(attrValue != null && !("selected".equalsIgnoreCase(attrLocalName) || "checked".equalsIgnoreCase(attrLocalName) || "disabled".equalsIgnoreCase(attrLocalName) )) {
							tag += ("=\"" + attrValue + "\"")
						}
					}
				}
			}
		}
		tag += ">"

		if(fullFag == true || seedoFag == true){	// 動的タグを記録する
			stackChange.top.setStartTagFull(tag)
			if(end){ // スラでタグが閉じている場合
				if(!stackChange.isEmpty){// Tag inside class="seedo" 
					stackChange.top.getBufChange.append(tag)	// 動的タグのオリジナルを設定
					tag += exec		// タグは、動的タグ生成側でタグ付けする。
					stackChange.pop	// The stack for substitution is liberated. 
				}
				out.print(tag)
			}
		} else {
			if(stackChange.isEmpty){
				out.print(tag)
			} else {	// 動的タグにネストするタグは置換対象となるため、このタグをバッファに蓄える
				stackChange.top.getBufChange.append(tag)
			}
		}
	}
	// タグエンド
	override def endElement (uri:String ,  name:String, qualifiedName:String):Unit={
		val endTag = "</" + name.toLowerCase +">"
		if(stackChange.isEmpty) {	// Tag to be substituted inside
			out.print(endTag)
		} else {
			stackChange.top.getBufChange.append(endTag)
	  		if(name.equalsIgnoreCase(stackChange.top.getStartTag)) {
	  			var str:String = null
				if(!stackChange.isEmpty){// Tag inside class="seedo" 
					str = stackChange.top.getStartTagFull + exec + endTag
					stackChange.pop	// The stack for substitution is liberated. 
				}
				if(stackChange.isEmpty){
					out.print(str)
				} else {// class="seedo" 動的タグがネストしている
					stackChange.top.getBufChange.append(str)
				}
	  		}
		}
	}
	// タグ以外
	override def characters(ch:Array[Char],start:Int,length:Int) : Unit = {
		var str:String = ""
		for(i <- start to length+start-1){
			str += ch(i)
		}
		if(stackChange.isEmpty){
			out.print(str)
		} else {// inside tag class="seedo"
			stackChange.top.getBufChange.append(str)
		}
	}
	// 動的タグを実行する
	def exec : String = {
		// Depth of the same stack as tag that became substitution beginning -> tag end
		var changeTag:String = ""
		val execCommand = stackChange.top.getExecCommand
		if(stackChange.top.getSeedo){ // SEEDO attribute
		  return create(execCommand)
		}
		val classname = execCommand(1)	// classnamesをNULLで関数呼び出ししてはいけない
		var method = ""
		try{
			var ec:ExecClass = new ExecClass(classname)		// Object is generated. 
			if(ec != null){
				ec.exec("setTag",stackChange.top.getBufChange.toString)	// TAG before it substitutes it is set. 
				ec.exec("setParameterMap",pMap)	// GetParameterMap method of ServletRequest to acquire parameter
				ec.exec("setSession",session)	// セッション情報を引き渡す
				if(execCommand.length == 3){	// Argument none
					method = execCommand(2)
					val result = ec.exec(method)
					if(result != null)
						changeTag = result.toString
				} else if(execCommand.length == 4){	// There is one argument. 
					method = execCommand(2)
					val value = execCommand(3)
					val result = ec.execStr(method,value)
					if(result != null)
					  changeTag = result.toString
				}
			}
		} catch {
			case e:NoSuchMethodException => {
				println("Exception "+e.getMessage + " NoSuchMethodException! :" + classname + " " + method)
			}
			case e:Exception => {
				println("Exception "+e.getMessage + " class or Method not find! :" + classname + " " + method)
			}
		}
		return changeTag
	}
	// Seedo 動的サブレットクラス・オブジェクトを生成する
	def create(classnames:Array[java language=".lang.String"][/java]) : String = {
		val classname = classnames(0)	// classnamesをNULLで関数呼び出ししてはいけない
		var method = ""
		var changeTag:String = ""
		var ec:ExecClass = null
		ec = createClasses.get(classname)
		try{
			if(ec == null){	// はじめてクラス名が現れた
				ec = new ExecClass(classname)		// Object is generated.
				if(ec != null){
					createClasses.put(classname, ec)		// 生成したクラス・オブジェクトを登録する
					ec.exec("setParameterMap",pMap)	// GetParameterMap method of ServletRequest to acquire parameter
					ec.exec("setSession",session)	// セッション情報を引き渡す
				}
			}
			if(ec != null){
				if(classnames.length == 2){	// Argument none
					method = classnames(1) 
					val result = ec.exec(method)
					if(result != null)
						changeTag = result.toString
				} else if(classnames.length == 3){	// There is one argument. 
					method = classnames(1) 
					val value = classnames(2)
					val result = ec.execStr(method,value)
					if(result != null)
						changeTag = result.toString
				}
			} else {
				println("Exception :Not create object = " + classname + " " + method)
			}
		} catch {
			case e:NoSuchMethodException => {
				println("Exception "+e.getMessage + " NoSuchMethodException! :" + classname + " " + method)
			}
			case e:Exception => {
				println("Exception "+e.getMessage + " class or Method not find! :" + classname + " " + method)
			}
		}
		return changeTag
	}
}

2012年1月4日

Java Object[] を Scala Array にてアクセス

Filed under: Scala — admin @ 12:16 AM

Javaで作ったDBクラスのSelect文の結果を、複数レコードをArrayListで、1レコードをObject[] 配列で返す仕様で作りました。

これをScalaで受け取るには、Java配列をScalaで使うには以下のように書きます。

val f: Array[Object] = record.asInstanceOf[Array[Object]]

これを使ったプログラム。

package ews.servlet

import seedo.database._
import java.io.PrintWriter

class db02 {
	def run(out:PrintWriter) : Unit = {
		val sqlplus = new SqlPlus
		try {
			val records = sqlplus.select("*").from("EMP").whereParam("EMPNO=? OR EMPNO=? OR ENAME=?",Array(new Integer(7788),new Integer(7521),"JONES") ).orderBy("ENAME").executeQuery
			out.println("<table border='1'>")
			for(i <- 0 to records.size-1) {
				val record = records.get(i)
				val f: Array[Object] = record.asInstanceOf[Array[Object]] 
				out.println("<tr>")
				for(j <- 0 to f.length-1) {
					out.println("<td>" + (if(f(j)!=null){f(j)}else{""}) + "</td>")
				}
				out.println("</tr>")
			}
			out.println("</table>")
		} finally {
			sqlplus.close
		}
	}
}

可変長引数

Javaの可変長引数についてJDK1.4で可変長引数を使えるように作った whereParam関数。
JDK1.5以降ではwhere関数は…で可変長引数が使える。

引数をArray配列にして渡します。

2012年1月3日

Herokuコマンド

Filed under: Scala — admin @ 2:09 AM

Herokuコマンドを使ってみて

パブリック・キーを生成する。

$ ssh-keygen -t rsa

パブリック・キーをHerokuに登録する。

$ heroku keys:add

ログインする

$ heroku login
Enter your Heroku credentials.
Email: xxxxx
Password:

リストする

$ heroku list
radiant-mountain-7703

情報を見る

$ heroku info --app radiant-mountain-7703
=== radiant-mountain-7703
Addons:        Basic Logging, Basic Release Management, Shared Database 5MB
Database Size: (empty)
Git URL:       git@heroku.com:radiant-mountain-7703.git
Owner:         kato@ewavesolutions.com
Repo Size:     74M
Slug Size:     17M
Stack:         cedar
Web URL:       http://radiant-mountain-7703.herokuapp.com/

設定を見る。

$ heroku config
DATABASE_URL        => postgres://qprrsjojjz:LF_nQwyKQ5vT4vMLGc5Y@ec2-107-21-110
-231.compute-1.amazonaws.com/qprrsjojjz
JAVA_OPTS           => -Xmx384m -Xss512k -XX:+UseCompressedOops
MAVEN_OPTS          => -Xmx384m -Xss512k -XX:+UseCompressedOops
PATH                => /usr/local/bin:/usr/bin:/bin
SHARED_DATABASE_URL => postgres://qprrsjojjz:LF_nQwyKQ5vT4vMLGc5Y@ec2-107-21-110
-231.compute-1.amazonaws.com/qprrsjojjz

ログを見る。

$ heroku logs
2012-01-02T14:09:23+00:00 heroku[router]: GET radiant-mountain-7703.her
okuapp.com/db dyno=web.1 queue=0 wait=0ms service=585ms status=200 bytes=2205
2012-01-02T14:10:36+00:00 heroku[router]: HEAD radiant-mountain-7703.he
rokuapp.com/db dyno=web.1 queue=0 wait=0ms service=613ms status=200 bytes=0
2012-01-02T14:40:14+00:00 heroku[router]: GET radiant-mountain-7703.her
okuapp.com/html dyno=web.1 queue=0 wait=0ms service=2588ms status=200 bytes=616
2012-01-02T15:46:06+00:00 heroku[web.1]: Idling
2012-01-02T15:46:07+00:00 heroku[web.1]: State changed from up to down

Herokuのプロセスを見る。

$ heroku ps
Process  State      Command
-------  ---------  --------------------
web.1    up for 1h  sh target/bin/webapp

Herokuのプロセスを再起動する。

$ heroku restart
Restarting processes... done

設定されているパブリック・キーを見る。

heroku keys

Heroku: Java Web Application using Embedded Tomcat & Scala

Filed under: Scala — admin @ 12:28 AM

Heroku を使っていろいろ試している人のページを参考にして何とかScalaで動くところまできています。

挑戦者に感謝!

最初はなかなかうまく動いてくれない。でも動くといろいろ試したくなります。

Herokuのローカル環境。
私の現在のフォルダ構成は以下の通りです。

Jetty版も動かしているのですが、
長年付き合ってきたTOMCATが好きです。

今回はじめて Embedded Tomcat を使ったのですが、ドキュメントがないのに苦労します。JAVADOCだけではよくわからないし。皆さんはどうやっているのでしょうか。

Main.javaでは、クラスローダーでJarファイルを独自に読み込むコードも書いてみたのですが、思い通りに動かないものです。

これも私の基礎がなっていことが原因なんですけどね。

2012年1月2日

Heroku Embedded Tomcat + Scala2.9.1 + Oracle Database

Filed under: Scala — admin @ 11:49 PM

ScalaでOracle11g データベースをJDBCドライバで純粋にアクセスするコードを書いてみます。

javax.servlet.annotation.WebServlet のアノテーションを使います。Tomcat7のServlet Ver3 ですから。

@WebServlet(Array(“/html”)) と書けるところがいい。

package ews.servlet

import java.io.IOException
import java.util.Date
import java.util._
import javax.servlet.ServletException
import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@WebServlet(Array("/html"))
class htmlSrv extends HttpServlet {
	override def doGet(request : HttpServletRequest, response : HttpServletResponse) : Unit = {
		val out = response.getWriter
		response.setContentType("text/html; charset=UTF-8");

		out.println("<html><body>")
		out.println("hello scala " + new java.util.Date)

		val db = new db01
		db.run(out)

		out.println("</body></html>")
		out.flush
		out.close
	}
}



OracleJDBCドライバのサンプルコードをScalaで書き換えます。

DriverManager のOracleサーバのIPアドレスは稼働するアドレスを指定します。(以下はサンプルです)

package ews.servlet

import java.io.IOException
import java.util.Date
import java.util._
import seedo.database._
import java.sql._
import oracle.jdbc._
import oracle.jdbc.pool.OracleDataSource
import java.io.PrintWriter

class db01 {
	def run(out:PrintWriter) : Unit = {
		// Oracle JDBC Driverのロード
		Class.forName("oracle.jdbc.driver.OracleDriver");
		// Oracle11g に接続
		val conn = DriverManager.getConnection("jdbc:oracle:thin:@111.111.111.111:1521:orcl11g", "scott", "tiger")
		// ステートメントを作成
		val stmt = conn.createStatement
		// 問合せの実行
		val rset = stmt.executeQuery("select EMPNO, ENAME from EMP order by ENAME")
		// 問合せ結果の表示
		out.println("<table>")
		while ( rset.next() ) {
			// 列番号による指定
			out.println("<tr><td>"+rset.getInt(1) + "</td><td>" + rset.getString(2)+"</td></tr>")
		}
		out.println("</table>")
		// 結果セットをクローズ
		rset.close
		// ステートメントをクローズ
		stmt.close
		// 接続をクローズ
		conn.close
	}
	def db : Unit = {
		// Prompt the user for connect information
		System.out.println("Please enter information to test connection to the database")
		var user = "scott"
		var password = "tiger"
		var database = "orcl11g"

		print("Connecting to the database...")
		println("Connecting...")
		// Open an OracleDataSource and get a connection
		val ods = new OracleDataSource
		ods.setURL("jdbc:oracle:thin:@111.111.111.111:1521:orcl11g");
		ods.setUser(user);
		ods.setPassword(password);
		val conn = ods.getConnection();
		println("connected.")

		// Create a statement
		val stmt = conn.createStatement

		// Do the SQL "Hello World" thing
		val rset = stmt.executeQuery("select 'Hello World' from dual")
		
		while (rset.next()){
			println(rset.getString(1))
		}
		// close the result set, the statement and the connection
		rset.close
		stmt.close
		conn.close
		println("Your JDBC installation is correct.");
	}
}



実際のHEROKUの画面はこんな感じです。

http://radiant-mountain-7703.herokuapp.com/html

ScalaでOKです。

このソースコードでの障害を1つ。

最初は、htmlSrv.scalaファイル1つだったのですが、

import java.sql._

を追加すると、

@WebServlet(Array(“/html”))

のArrayクラスが定義できないとコンパイラからエラー。

これはjava.sql._ライブラリにArrayクラスが独自に定義されていることが原因。

面倒なので、別のクラスにして逃げています。

こんなもんのです。プログラム作るってことは。

Older Posts »

Powered by WordPress