TOMCATとScalaとの関係ができあがったところで、
このWeb Framework についての仕様を決めましょう。
LiftやApache Wicket のようにHTMLファイルをベースにします。
その理由は、
- WebページのデザインはやはりプロであるWebデザイナが行うことが重要。
機能的に優れていても見た目や構成がダメならページを見てもらえない。
- ページを表示するディバイスがPCのブラウザだけではなく、
スマートフォンや携帯電話、タブレットと多様化し、
各ディバイスに最適なデザインはWebデザイナが分担して作業を進める。
- 頻繁にページを更新することはもはや日常茶飯事。
ページ更新するたびにTOMCATを再起動できない。
- Webページをデザインするツールは動的ページのことなど考えていない。
メニューやお知らせもデザインツールで簡単に生成でき、そのままFTPでWebサイトへ更新できる。
- 既存Webサイトからの移行にいちいちコンバート作業なんてしてられない。
ということで、
「HTMLファイルありき」がこのWeb Framework の第一の方針です。
次に、運用の観点から
TOMCATなどJavaVMを使ったWebサーバの弱点はメモリー管理です。
運用経験がある担当者であれば一度はOutOfMemoryError すなわちメモリ不足に陥ったことがあるでしょう。
メモリのガーベージコレクト(GC)に時間がかかるようになったりすると、
JVMのGCのパラメータをいろいろ変えたり、64ビット版JDKへ移行するためにプラットフォームを32Bから64Bに入れ替えたりと大変です。
JVMにはPermanent領域と呼ばれるヒープ領域があり、クラス定義やメソッド、フィールドなどのメタデータが格納されます。
JSPでページ構成を作るとこの領域に格納されます。Servletも同じ。
Permanent領域を抑えるためには、クラスの数を少なくすること。
1日目のServletを1つにする理由はここにあります。
ページが増えてもクラスが増えないようにすることです。
JSPだとページまるごとクラスとなるのでかなりクラスが大きくなります。
HTMLファイルを読み込み、動的に情報を表示する領域のためのオブジェクトによって動的ページを生成して、
元のHTMLファイルを置換するという方式です。
これが第2の方針
JSPのように最初のアクセスでコンパイルの必要もなく、
Apache httpd のようにDocumentRootディレクトリにHTMLファイルを置くだけです。
このプログラムのしくみはいたって簡単。
- Servletのパラメータで指定されたHTMLファイルを読みこんで
- toString関数でString型にする
プログラムは積み上げて構築していくものという考えなのでスタートはここから。
package ews import java.io._ import javax.servlet.http._ /** * HTML file -> read -> String ----> Servlet response output */ class StraightSp (request : HttpServletRequest, response : HttpServletResponse, htmlPath : String) extends TemplSp { var parsed:String = "" // replace HTML def html : String = { try { val htmlFile = new java.io.File(htmlPath) if(htmlFile.exists && htmlPath.toLowerCase.endsWith(".html")){ // open HTML file val bis = new InputStreamReader(new FileInputStream(htmlFile),"UTF-8") val dis = new BufferedReader(bis) while(dis.ready) { val str = dis.readLine parsed += str } } return parsed } catch { case e:IOException => { println("IOException "+e.getMessage) } } null // There is no file. } override def toString :String = parsed }
しかし、これではTOMCATのプロジェクトディレクトリにHTMLファイルを置くのと同じ
2つ目のプログラム。HTMLファイルをXMLローダで読み込んでみる。
package ews import javax.servlet._ import javax.servlet.http._ import scala.xml._ /** * HTML file -> XML.loadFile */ class XmlSp (request : HttpServletRequest, response : HttpServletResponse, htmlPath : String) extends TemplSp { var parsed:String = null var xml:scala.xml.Node = null // replace HTML def html : String = { try { val htmlFile = new java.io.File(htmlPath) if(htmlFile.exists && htmlPath.toLowerCase.endsWith(".html")){ xml = XML.loadFile(htmlPath) if(xml != null) parsed = xml.toString } return parsed } catch { case e:Exception => { println("Exception "+e.getMessage) } } null // There is no file. } override def toString :String = parsed }
このプログラムの仕様は、HTMLファイルをscalaのXML.loadFile で読みこんでしまう。
これは少々無謀。
とうぜん、HTMLはXMLではないので既存のHTMLファイルを読めばエラーの嵐。
問題個所は、空白文字  ;
<BR>や<HR>、<IMG>のように単独で記述するタグ。
scala が XML を型として使えるといえども、HTMLを扱うには問題あり。
こうなると、HTMLパーサを導入することが妥当な選択
2つのHTMLパーサを試してみます。
javax.swing.text.html.parserとnu.validator.htmlparser
javax.swing.text.html.parserでは、
package ews import java.io._ import javax.servlet.http._ import javax.swing.text._ import javax.swing.text.html._ import javax.swing.text.html.parser._ import javax.swing.text.html.parser.ParserDelegator import scala.xml._ /** * HtmlParse */ class Htmlparse2Sp (request : HttpServletRequest, response : HttpServletResponse, htmlPath : String) extends TemplSp { var parsed:String = null // override def toString :String = parsed // replace HTML def html : String = { val htmlFile = new java.io.File(htmlPath) if(htmlFile.exists && htmlPath.toLowerCase.endsWith(".html")){ try { val input = new InputStreamReader (new FileInputStream(htmlFile), "UTF-8") // open HTML file val cb = new ParserCallback2 val pd = new ParserDelegator pd.parse(input, cb, true) input.close parsed = cb.toString return parsed } catch { case e:IOException => { println("Exception "+e.getMessage) } } } null // There is no file. } }
ハンドラクラスは以下のとおり
class ParserCallback2 extends HTMLEditorKit.ParserCallback { var buf = new StringBuffer override def toString :String = buf.toString override def handleStartTag(tag:HTML.Tag, attrs:MutableAttributeSet , pos:Int):Unit={ buf.append("
nu.validator.htmlparserでは、
package ews import java.io._ import javax.servlet.http._ import scala.xml._ import scala.xml.parsing.{ConstructingParser,NoBindingFactoryAdapter} import nu.validator.htmlparser.common.XmlViolationPolicy import nu.validator.htmlparser.sax.{HtmlParser,XmlSerializer,HtmlSerializer} import nu.validator.htmlparser.test.SystemErrErrorHandler /** * HtmlParse */ class HtmlparseSp (request : HttpServletRequest, response : HttpServletResponse, htmlPath : String) extends TemplSp { var parsed:String = null // override def toString :String = parsed // replace HTML def html : String = { val htmlFile = new java.io.File(htmlPath) if(htmlFile.exists && htmlPath.toLowerCase.endsWith(".html")){ try { val input = new BufferedInputStream(new FileInputStream(htmlFile)) // open HTML file val inputSource = new InputSource(input) val parser = new HtmlParser parser.setNamePolicy(XmlViolationPolicy.ALLOW) val saxer = new NoBindingFactoryAdapter parser.setContentHandler(saxer) parser.setErrorHandler(new SystemErrErrorHandler) parser.parse(inputSource) parsed = saxer.rootElem.toString.replaceAll("<br></br>","<br>") return parsed } catch { case e:IOException => { println("Exception "+e.getMessage) } } } null // There is no file. } }
このHTMLパーサはLiftでも使われているとのこと。
2つのHTMLパーサを試してみましたが、
いよいよ、
ハンドラクラスでの動的ページ生成のロジックの組み込みとなります。
コメントを残す
コメントを投稿するにはログインしてください。