GSPにpageEncodingディレクティブを作ってみた!
結局Parseクラスのパッチを作ってみた。最初にScanクラスでトークンを読み出してみて、pageEncodingディレクティブがあったらそれで再度Scanクラスのインスタンスを生成することにした。あんまり効率よくなさそう...
注)以下のパッチには不備があることが判明しています。詳細はここ。
Index: Parse.java =================================================================== --- Parse.java (revision 4321) +++ Parse.java (working copy) @@ -36,6 +36,7 @@ * * Date: Jan 10, 2004 * + * Added by pageEncoding directive by Norihiro Seto */ public class Parse implements Tokens { public static final Log LOG = LogFactory.getLog(Parse.class); @@ -60,6 +61,8 @@ private String contentType = "text/html;charset=UTF-8"; private boolean doNextScan = true; private int state; + private ByteArrayOutputStream streamContent; + private String pageEncoding; public String getContentType() { @@ -80,6 +83,7 @@ public Parse(String name, InputStream in) throws IOException { scan = new Scan(readStream(in)); + scanPageEncoding(); makeName(name); } // Parse() @@ -129,6 +133,7 @@ String value = mat.group(2); if (name.equals("import")) pageImport(value); if (name.equals("contentType")) contentType(value); + if (name.equals("pageEncoding")) pageEncoding(value); ix = mat.end(); } } // directPage() @@ -208,6 +213,50 @@ return 0; } // match() + private void pageEncoding(String value) { + this.pageEncoding = value; + } + + private void scanPageEncoding() throws IOException { + if (LOG.isDebugEnabled()) LOG.debug("parse: scanPageEncoding"); + int stateBkup = state; + boolean doNextScanBkup = doNextScan; + out = new GSPWriter(new StringWriter(), this); + try { + loop: for (;;) { + if(doNextScan) + state = scan.nextToken(); + else + doNextScan = true; + + switch (state) { + case EOF: break loop; + case JDIRECT: direct(); break; + case GDIRECT: direct(); break; + } + if (pageEncoding != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("parse: scanPageEncoding encoding=" + + pageEncoding); + } + scan = new Scan(streamContent.toString(pageEncoding)); + break; + } + } + } + finally { + state = stateBkup; + doNextScan = doNextScanBkup; + streamContent = null; + try { + out.close(); + } + catch (Exception ignore) {} + out = null; + scan.reset(); + } + } // scanPageEncoding() + private void page() { if (LOG.isDebugEnabled()) LOG.debug("parse: page"); if (finalPass) { @@ -450,6 +499,7 @@ if (read <= 0) break; out.write(buf, 0, read); } + streamContent = out; return out.toString(); } finally { out.close();
テストクラスのパッチは、これ
Index: ParseTests.java =================================================================== --- ParseTests.java (revision 4321) +++ ParseTests.java (working copy) @@ -82,6 +82,45 @@ assertEquals(trimAndRemoveCR(expected), trimAndRemoveCR(output)); } + public String parseCodeBytes(String uri, byte[] gsp) throws IOException { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + InputStream gspIn = new ByteArrayInputStream(gsp); + Parse parse = new Parse(uri, gspIn); + InputStream in = parse.parse(); + send(in, pw); + + return sw.toString(); + } + + public void testParseWithPageEncoding() throws Exception { + String output = parseCodeBytes("myTest", ( + "<%@ page pageEncoding=\"utf-8\" import=\"some.test.package.*\"%>" + + "<div>\u3053\u3093\u306b\u3061\u306f[Japanese]</div>" + ).getBytes("utf-8")); + String expected = + "import org.codehaus.groovy.grails.web.pages.GroovyPage\n" + + "import org.codehaus.groovy.grails.web.taglib.*\n"+ + "import some.test.package.*\n" + + "\n"+ + "class myTest extends GroovyPage {\n"+ + "public Object run() {\n"+ + "out.print('<div>\u3053\u3093\u306b\u3061\u306f[Japanese]</div>')\n"+ + "}\n"+ + "}"; + +// System.out.println(output); + assertEquals(expected, trimAndRemoveCR(output)); + + String output2 = parseCodeBytes("myTest", ( + "<%@ page import=\"some.test.package.*\"%><%@ page pageEncoding=\"utf-8\"%>" + + "<div>\u3053\u3093\u306b\u3061\u306f[Japanese]</div>" + ).getBytes("utf-8")); + +// System.out.println(output2); + assertEquals(expected, trimAndRemoveCR(output2)); + } + /** * Copy all of input to output. * @param in
単体テストは成功することは確認した。実際にアプリケーションを動作してのテストはしていない。