久しぶりにパーサー部分に機能追加
いままでの動的動作は毎回クラスからオブジェクトを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 } }