Web フレームワークを作る!!  2日目

Posted 2011年8月20日 by

TOMCATとScalaとの関係ができあがったところで、
このWeb Framework についての仕様を決めましょう。

LiftApache Wicket のようにHTMLファイルをベースにします。

その理由は、

    1. WebページのデザインはやはりプロであるWebデザイナが行うことが重要。
      機能的に優れていても見た目や構成がダメならページを見てもらえない。
    1. ページを表示するディバイスがPCのブラウザだけではなく、
      スマートフォンや携帯電話、タブレットと多様化し、
      各ディバイスに最適なデザインはWebデザイナが分担して作業を進める。
    1. 頻繁にページを更新することはもはや日常茶飯事。
      ページ更新するたびにTOMCATを再起動できない。
    1. Webページをデザインするツールは動的ページのことなど考えていない。
      メニューやお知らせもデザインツールで簡単に生成でき、そのままFTPでWebサイトへ更新できる。
  1. 既存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ファイルを置くだけです。

このプログラムのしくみはいたって簡単。

    1. Servletのパラメータで指定されたHTMLファイルを読みこんで
    1. 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>のように単独で記述するタグ。

&nbsp;


scala が XML を型として使えるといえども、HTMLを扱うには問題あり。

こうなると、HTMLパーサを導入することが妥当な選択

2つのHTMLパーサを試してみます。

javax.swing.text.html.parsernu.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パーサを試してみましたが、

いよいよ、
ハンドラクラスでの動的ページ生成のロジックの組み込みとなります。

Post Details

  • Post Title: Web フレームワークを作る!!  2日目
  • Author: admin
  • Filed As: Framework, Scala
  • Tags:
  • You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

コメントを残す