Web Flavor

[English] [日本語]

Top Screenshot Manual Download Wiki Chat

1 Abstract 2 Getting started 3 Download 4 License 5 Contact 6 Postscript Appendix

Version 0.3.0a2
2008.10.22

1 Abstract

1.1 Introduction

I have been looking for a framework to make Web application easily, but I was not satisfied the existing ones. I think that the idea of scriptlet of JSP is a good way to ease of development.

Therefore, using the JSP cocept, I developed the Web framework with the following features:

The previous versions of Web flavor 0.1 can use with Rhino (JavaScript) or JRuby (Ruby), however, this version is only for Scala in order to utilize features of Scala.

"Better CGI, Better PHP!"

The environment without strong constraint but which enable to develop easily as CGI or PHP, the loose but enough for Web application development --- that is my goal.

1.2 Feature

The features of Web Flavor version 0.3 are:

2 Getting started

2.1 Runtime Requirement Environment

Web Flavor requires:

Java Java 5 Runtime Environment or later
Java Servlet Java Servlet 2.3 or later
Java Servletコンテナ Apache Tomcat 6 or later (Tomcat 5 might be compatible but it has not be confirmed. Other containers such as Jetty are not tested.)
Scala 2.7.1.final (included)

Because we have not tested every combination of the above environment, some might not work well.

2.2 Installing Web Flavor

Deploy ${WEB_FLAVOR_HOME}/webflavor.war on the servlet container.

Add ${WEB_FLAVOR_HOME}/lib/scala-library.jar to the CLASSPATH of the servlet container, or it might not work on some servlet containers.

2.3 What is Flavor?

Flavor is a script for Web application, and is written by Scala language.

In Web Flavor, a web application is developed by writing Flavors.

Details of Flavor are shown in "A3 Flavor".

2.4 Deployment of Flavor source and Mapping Rules of Access Path

A Flavor source is to be deployed in the directory WEB-INF/src/, and the relative path of the source is mapped to its access path in the same way.

作成したFlavorソースは、WEB-INF/src/下に置かれ、その相対パスがそのままアクセスパスにマッピングされます。

For example:

Flavorソース URL
WEB-INF/src/examples/Foo.scala http://localhost:8080/webflavor/examples/Foo.scala

Details are shown in "A4 Deployment of Flavor source" and "A5 Mapping Rules of Access Path".

2.5 API

Java Servlet API are provided with wrapping of Scala to be easily used in Flavors.

Details are shown in "A2 API Reference".

2.6 Flavor Programming

Flavor programming is explained with examples as follows:

2.6.1 Hello, world!

As a first example, let us make a Flavor which displays "Hello, world!."

// HelloWorld.scala

// Title
val TITLE = "Hello, world!"

// An XML element to be returned to
// Web Flavor engine as response.
<html><body><h1>{TITLE}</h1></body></html>

Save the Flavor (Scala script) as HelloWorld.scala in WEB-INF/src/. The character set of the file should be UTF-8.

Though it looks like a mere HTML template, actually, it is a Scala code. It might be hard to understand because the return value of the code is not explicitly expressed.

The last line is equivalent to the statement

return <html><body><h1>{TITLE}</h1></body></html>

(In Scala, return keyword is omitted usually.)

In this sample code, it returns an XML element, but returning String or null is possible.

2.6.2 Echo

リクエストしたパラメータなどを表示するFlavorを作ります。

// Echo.scala

// Title
val TITLE = "Echo"

// An XML element to be returned to
// Web Flavor engine as response.
<html>
<head>
<title>{TITLE}</title>
</head>
<body>
<h1>{TITLE}</h1>
<h2>Headers:</h2>
{for ((name, value) <- request.headers) yield <p>{name}: {value}</p>}
<h2>Parameters:</h2>
{for ((name, value) <- request.params) yield <p>{name}: {value}</p>}
</body>
</html>

Save the Flavor as Echo.scala in the directory WEB-INF/src/.

The "request" in the code is an instance equivalent of HttpServetRequest. The header and parameter information are provided as request.headers and request.params respectively with type of Map[String,String].

As both are Seq[String,String], they are iterable in for-loops to obtain the contained information.

2.6.3 POHP Template

The version 0.2.7 or later allows HTML page generation using POHP (Plain Old HTML Page).

This feature enables sepalation of View as HTML template, and pure HTML template allows collabolation with web designer.

To write "Hello, world!" Flavor with POHP, make the following HTML template as src/POHPHelloWorld.html . The character set should be UTF-8.

<html>
<head>
<title><span flavor:id="title">title</span></title>
</head>
<body>
<h1><span flavor:id="title"/></h1>
<span flavor:id="message">Hello</span>
</body>
</html>

The element <span flavor:id="resourceName"/>...</span> is the resource to be embedded.

Next, save the following Flavor as src/POHPHelloWorld.scala with character encoding of UTF-8.

Template("",
  "title" -> Text("Hello, world!"),
  "message" -> <p>Hello, POHP world!</p>
)

Template("pageName", (String,Seq[scala.xml.Node])*) is a method to generate template object.

"title" -> Text(...) describes the resource to be inserted. The resource is an object with type of Seq[scala.xml.Node], and an XML element such as an XML-literal is available as a resource. The text has to be converted to an XML element by Text(...) method.

The template file and the flavor source file have to be in the same directory and the same filename with suffixes of ".html" and ".scala" respectively.

By doing above, HTML page with substitution of resource can be displayed.

<html>
<head>
<title>Hello, world!</title>
</head>
<body>
<h1>Hello, world!</h1>
<p>Hello, POHP world!</p>
</body>
</html>

The Flavor of the same URL can respond different pages. If "src/POHPHelloWorld.scala" is as following,

Template("Foo",
  "title" -> Text("Hello, world!"),
  "message" -> <p>Hello, POHP world!</p>
)

とした場合、対象となるテンプレートは"src/POHP_HelloWorld_Foo.html"となり、ページ名と名前の組み合わせにより、複数ページを返すことが可能になります。

the targeted HTML template changes to "src/POHP_HelloWorld_Foo.html". Combinations of page name and name(名前って何のこと?) enable different pages. Default page name is "" (empty string). Details of POHP template are shown in "A9 POHP Template".

2.6.4 注意点

If the type of the object which is persistent, such as Context#attributes or Session, is defined in a Flavor source, updating the flavor souce may cause ClassCastException.

It is caused by the difference of the class space (ClassLoader) between the persistent object and the newly created class. It cause the exception continuously until restart of the servlet container or deployment.

To solve this problem,

2.6.5 Dynamic Library

Dynamic library is the library used in Flavors, is compiled with Flavors, and is executed on the same ClassLoader.

Dymanic library enables to share codes used in Flavors.

It also allows try-and-error development because it is compiled dynamically. Details are shown in "A10 Dymanic Library".

2.6.6 Flavor Compiler

Version 0.25 or later allows to compile Flavors in advance to package as web application.

It's merit is:

It is suited for operating the developed programs as package.

The development process is

  1. Write libraries for Flavor, and compile them
  2. Write Flavor source
  3. Compile Flavor by "flavorc" command or flavorc Ant task
  4. Package needed classes and libraries as jar- or war-file
  5. Deploy the package on a servlet container

flavorcコマンドやflavorc Antタスクについては、「A8 Flavor Compiler」をご覧ください。

"flavorc" command and flavorc Ant task are described in "A8 Flavor Compiler".

To deploy on a servlet container, the web.xml should be modified as follows:

  <filter>
    <filter-name>WebFlabor</filter-name>
    <filter-class>
      jp.ne.cappuccino.keisuken.servlet.flavor.WebFlavorFilter
    </filter-class>
...
    <init-param>
      <param-name>staticMode</param-name>
      <param-value>true</param-value>
    </init-param>

By setting staticMode to true, Flavor is excuted statically and is not compiled dynamically.

2.6.7 Sample Sources

In WEB-INF/src directory, there are sample sources.

2.7 Administrator menu

Version 0.2.0a3 or later has an administrator menu, which administrates Web Flavor. Current version allows

This feature enables editing and executing Web Flavors from web brouser, which means easy and rapid development of web applications. Administrator manu is also written in Flavor.

Details are shown in "A7 Administrator menu".

2.8 Demonstration Package

Download WebFlavor-samples-x.x.x.zip and expand it. Set an environment variable JAVA_HOME or JRE_HOME to the Java runtime home directory (such as C:¥Program Files¥java¥jre¥1.6.0_07). Execute startup.bat (WINDOWS) or start.sh (UNIX) in WebFlavor-samples directory.

By accessing http://localhost:8080/, sample applications are executed.

As Administrator menu requires BASIC authentication, login with username: webflavor and password: webflavor.

3 Downloads

以下のページからダウンロードできます.

https://sourceforge.net/project/showfiles.php?group_id=242794

アーカイブ 詳細
WebFlavor-#.#.#.zip ソースとWARファイルパッケージ
WebFlavor-samples-#.#.#.zip サンプルアプリケーション(Apache Tomcat込)

以下のページからダウンロードできます.

4 ライセンス

ライセンスファイルを参照してください.

なお,このソフトウェアを使って生じた損害などについては,作者である西本 圭佑は一切責任をとりませんのでご了承ください.

また,Scalaなどのランタイムについても,各ライセンスファイルをご覧下さい.

5 連絡先

質問や要望などがありましたら keisuken atmark cappuccino.ne.jp あるいは Twitterの @keisuke_n まで内容を書いてお送りください.

6 最後に

Administrator menuでソースの生成から編集までできるようになり、ちょっとしたCGIぽいものをServletコンテナ上で試すことができ、Scalaの記述性も助けて、便利に使えるものになったと思います。

パフォーマンスも、コンパイルに時間がかかることに目をつぶれば、生のJava Servletと同じくらいのパフォーマンスが出ると思います。

JSPのScriptletでも短いものは同様に軽快に書けていけますが、JSPの記述ルールをある程度覚えなくてはいけなかったり、XMLのタグの中にコードが埋もれてしまって、読みにくく書きにくいものになっています。

Web FlavorではScalaのコードのみ許すことによって、読みやすさや書きやすさを追求できますし、XMLリテラルがあるために、Viewをかなり簡単に記述できます。XSS(クロスサイトスクリプティング)が生じにくくなる良い副作用もあります。

通常ViewとControllerを混ぜて記述するのは推奨されせんが、Web FlavorではViewとController、場合によってはModelまで1つのソースファイルに書いてしまいます。しかし「それでもいい」と思わせてしまう魅力を持っていると思います。

しかしまだ未完成です.APIなどの仕様が大幅に変更される可能性がありますし,バグもたくさんあります、ドキュメントもまだまだ十分とはいえませんが、これからも改良していきたいと思います。応援してください。

Appendix

A1 Reqired Runtime Environment

Web Flavor requires:

Java 5 Runtime Environment以上
Java Servlet Java Servlet 2.3以上
Java Servletコンテナ Apache Tomcat 6以上(Tomcat 5以降でも動作すると思われる, Jettyなど他のコンテナは未確認)
Scala 2.7.1.final (標準添付)

A2 API Reference

APIリ Reference

Flavor API

Flavor API is for handling resources and configuration to write Flavor.

Flavor GUI(FORM) API

Flavor GUI API is a kind of framework to write FORM in Flavor.

GUI component (which displays input element and holds inputed values) and validator (which validates inputed values) are provided.

A3 Flavor

A Flavor is a script for web application written in Scala.

A3.1 Writing Rules

Flavors shall be written with the following rules:

A3.2 Flavor source

Character code os Flavor source is UTF-8 (fixed.)

Flavor source is a closure (class) which inherits,

and variables such as context, request, response, and sessions are passed as arguments of closure.

As Web Flavor engines adds closure (class) declarations shown below automatically, only content of closures are required to write.

import jp.ne.cappuccino.keisuken.servlet.flavor.{Context,Request,Response,FlavorUtils}
import jp.ne.cappuccino.keisuken.servlet.flavor.HTMLUtils._
import java.io._

class {名前} extends (Context,Request,Response,Session) => AnyRef {
  def apply(
    context: Context,
    request: Request,
    response: Response,
    session: Session): AnyRef = {
    val __flavor_util__ = new FlavorUtils(context, request, response, session)
    import __flavor_util__._
// A Flavor source is inserted here
  }
}

Returned values are handled as Servlet response and displayed as

返り値 出力
null No output
String String
scala.xml.Node(XML literal) XML/(X)HTML
Template(POHP Template) XML/(X)HTML
Book(null/String/scala.xml.Node/Temlate etc.) No output/String/XML/(X)HTML

Output can be configured with

For example,

response.contentType = "text/plain; charset=Windows-31J"

makes output as text format with Windows-31J encoding.

Basic procedure is to write a code that returns response object as follows:

A3.3 Output which conforms HTML 4.01 and XHTML 1.0

An XML element of Scala is useful and it can be use as a template, however, can not output HTML pages which conforms with (X)HTML.

By setting HTML type in reponse.documentType, HTML generated from XML element conforms (X)HTML.

HTML constants are

Constant (X)HTML/XML Type
HTML_4_01_STRICT HTML 4.01 Strict Type
HTML_4_01_TRANSITIONAL HTML 4.01 Transitional Type
XHTML_1_0_STRICT XHTML 1.0 Strict Type
XHTML_1_0_TRANSITIONAL XHTML 1.0 Transitional Type
XML_1_0 XML 1.0

An example is shown as follows:

// Write your code
...

// Set HTML type as XHTML 1.01 Transitional
response.documentType = XHTML_1_01_TRANSITIONAL

// XML object to output
<html>
<body>
</body>
</html>

By setting Response#documentType,

For html element, it outputs as written in XML elements, therefore, the developer should define attributes such as xmlns or xml:lang.

A3.4 Implicit method

In Flavor sources, the class

is instantiated and imported, therefore, its methods are available.

A4 Flavor Source Deployment

Flavor sources are to be deployed in directory WEB-INF/src/ . The deployed sources are compiled and executed at need.

Examples

A5 Mapping Rules of Access Path and Flavor Source

If Web Flavor is deployed as http://localhost:8080/webflavor/, mapped as follows:

URL path Flavor source path
/webflavor/Foo.scala WEB-INF/src/Foo.scala
/webflavor/Foo WEB-INF/src/Foo.scala
/webflavor/ WEB-INF/src/Index.scala
/webflavor/Index WEB-INF/src/Index.scala
/webflavor/Index.scala WEB-INF/src/Index.scala
/webflavor/examples/Boo.scala WEB-INF/src/examples/Boo.scala
/webflavor/examples/Boo WEB-INF/src/examples/Boo.scala

If access path ends with "/", it is handles as ".../index.scala".

A6 Web Flavor filter (web.xml) Configuration

Web Flavor filter is a runtime for Web Flavor and implemented as servlet filter.

Default configuration (web.xml) is as follow:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
    version="2.5">
...
  <filter>
    <filter-name>WebFlabor</filter-name>
    <filter-class>
      jp.ne.cappuccino.keisuken.servlet.flavor.WebFlavorFilter
    </filter-class>
    <init-param>
      <param-name>filterChain</param-name>
      <param-value>false</param-value>
    </init-param>
<!--
    <init-param>
      <param-name>source</param-name>
      <param-value>WEB-INF/src</param-value>
    </init-param>
    <init-param>
      <param-name>libSource</param-name>
      <param-value>WEB-INF/lib_src</param-value>
    </init-param>
    <init-param>
      <param-name>temporary</param-name>
      <param-value>WEB-INF/temp</param-value>
    </init-param>
    <init-param>
      <param-name>startupCompileAll</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>updateCheckInterval</param-name>
      <param-value>60</param-value>
    </init-param>
    <init-param>
      <param-name>staticMode</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>bbsHome</param-name>
      <param-value>/WEB-INF/bbs_data</param-value>
    </init-param>
    <init-param>
      <param-name>wikiHome</param-name>
      <param-value>/WEB-INF/wiki_data</param-value>
    </init-param>
-->
  </filter>

  <filter-mapping>
    <filter-name>WebFlabor</filter-name>
    <url-pattern>/</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>WebFlabor</filter-name>
    <url-pattern>/Index.scala</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>WebFlabor</filter-name>
    <url-pattern>*.scala</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>WebFlabor</filter-name>
    <url-pattern>/samples/*</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>WebFlabor</filter-name>
    <url-pattern>/admin/*</url-pattern>
  </filter-mapping>

It is mapped to "/"、"/Index.scala"、"*.scala"、"/samples/*"、"/admin/*".

Web Flavor Filter has following parameters:

パラメータ名 内容
filterChain Used for chaining filters. Default is "fale". In case of "true", filters are chained.
source The directory where Flavor sources are to be deployed. Default is "WEB-INF/src". If modified, it shall be designated by the relative path from the directory where the WAR file is deployed.
libSource The directory for dymanic libraries that Flavor sources depend. Default is "WEB-INF/lib_src". If modified, it shall be designated by the relative path from the directory where the WAR file is deployed.
temporary Temporary directory for Flavor compilation. Default is "WEB-INF/temp". If modified, it shall be designated by the relative path from the directory where the WAR file is deployed.
startupCompileAll Whether all Flavor sources are compiled or not on startup. Default is false, and they are not compiled. In case of true, all of them are compiled, and it may cause delay of startup.
updateCheckInterval Time interval (in second) to check modification of Flavor sources. Default is 60 seconds.
staticMode Whether Flavors are static mode (which instantiates from static class) or not. Default is false. In case of true, it generates Flavors from default class loader and executes them. In static mode, it starts up faster because of pre-compilation. However, it does not compile dynamically.

A7 Administrator menu

Administrator menu is an administrative menu of Web Flavor.

It provides the function to

Security configuration (in web.xml) is as follows. The menu is BASIC authenticated with "web-flavor-admin" roll. Change if you need.

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Admin area</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>web-flavor-admin</role-name>
    </auth-constraint>
  </security-constraint>

  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Admin area</realm-name>
  </login-config>

A8 Flavor Compiler

A8.1 Flavor Compiler Command

Set PATH to $FLAVOR_HOME/bin for flavorc (UNIF/Linux shell) or flavorc.bat.

Arguments for flavorc are

Usage: flavorc CLASSPATH DESTDIR SRCDIR
CLASSPATH: CLASSPATH needed to compile
DESTDIR: Directory for compiled classes
SRCDIR: Directory for Flavor sources

A8.2 Flavor Compiler Ant Task

To use flavorc Ant task, the custom task is required to define in Ant task.

<taskdef name="flavorc"
  classname="jp.ne.cappuccino.keisuken.servlet.flavor.tools.FlavorCompilerTask"
  classpath="${scala-compiler-jar}:${scala-library-jar}:${webflavor-jar}"
/>

Next, compilation is defined with flavorc Ant task.

<!--
${classpath}: CLASSPATH needed to compile
${destdir}: Directory for compiled classes
${srcdir}: Directory for Flavor sources
-->
<flavorc
  srcdir="${flavor-srcdir}"
  destdir="${classes}"
  classpath="${classpath}"
/>

A9 POHP Template

A9.1 POHP Template

POHP Template is an HTML file written in UTF-8.

Embedding XML resourses given by Flavor into this template, the final page (HTML/XHTML) is outputed.

A9.2 Naming Rules for POHP Template

Deploy wiith a same name and in the same directory of Flavor source. Suffix ".html" is required.

Flavor source path HTML template path
src/examples/Foo.scala src/examples/Foo.html

A9.3 POH Resource

Put resorce tag into the place in POHP template where you want to inject from Flavor.

<!-- src/examples/Foo.html -->
<html>
<body>
<span flavor:id="foo">dummy message</span>
</body>
</html>

There are two formats for resource tag.

Flavor is described as follows:

// src/examples/Foo.scala
Template("page name",
  "foo" -> <h1>Hello, world!</h1>
)

The XML element (Seq[scala.xml.Node]) given by the resource name is inserted into the place of the resource tag in Foo.html.

Naming rules of POHP templates are as follws:

Flavor path Page name HTML template path
examples/Foo.scala "" examples/Foo.html
examples/Foo.scala "boo" examples/Foo_boo.html
exmaples/Foo.scala "bar" examples/Foo_bar.html

A10 Dynamic Libralies

A10.1 Dynamic Libraries

Dynamic libraries are the libraries which depends on Flavor and is determined dynamically. They are compiled with Flavors dynamically, and executed on the same ClassLoader of Flavor.

Dynamic libraries enables sharing codes of web application and developing with try-and-error.

A10.2 Deplyment of Dynamic Libraries

Dynamic libraries are usually deployed in "WEB-INF/lib_src" and referenced by Flavors.

A10.3 Package

Because they cannot be referenced by root package, they have to be packaged.

// WEB-INF/lib_src/examples/HelloWorld.scala
package examples

object HelloWorld {
  def message = "Hello, world!"
}

A11 履歴

A12 ToDo