//----------------------------BEGIN LICENSE----------------------------
/*
* Willow : the Open Source WorkFlow Project
* Distributable under GNU LGPL license by gun.org
*
* Copyright (C) 2004-2010 huihoo.org
* Copyright (C) 2004-2010 ZosaTapo <dertyang@hotmail.com>
*
* ====================================================================
* Project Homepage : http://www.huihoo.org/willow
* Source Forge : http://sourceforge.net/projects/huihoo
* Mailing list : willow@lists.sourceforge.net
*/
//----------------------------END LICENSE-----------------------------
package org.huihoo.workflow.rules.compiler;
import java.io.CharArrayWriter;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.huihoo.workflow.rules.Constants;
import org.huihoo.workflow.rules.ScriptException;
import org.huihoo.workflow.rules.util.StringManager;
/**
* @author reic
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class Parser
{
private static StringManager sm =
StringManager.getManager(Constants.RESOURCE_BUNDLE_BASE);
/**
* The input source we read from...
*/
private ScriptReader reader;
/**
* The backend that is notified of constructs recognized in the input...
*/
private ParseEventListener listener;
/*
* Char buffer for HTML data
*/
CharArrayWriter caw;
/*
* Marker for start and end of the tempate data.
*/
Mark tmplStart;
Mark tmplStop;
String currentFile;
public interface Action
{
void execute(Mark start, Mark stop) throws ScriptException;
}
public Parser(ScriptReader reader, final ParseEventListener lnr)
{
this.reader = reader;
this.listener = new DelegatingListener(lnr, new Action()
{
public void execute(Mark start, Mark stop) throws ScriptException
{
Parser.this.flushCharData(start, stop);
}
});
this.caw = new CharArrayWriter();
this.currentFile = reader.mark().getFile();
}
static final Vector coreElements = new Vector();
/*
* Godj directives
*/
static final class Directive implements CoreElement
{
private static final String OPEN_DIRECTIVE = "<%@";
private static final String CLOSE_DIRECTIVE = "%>";
static final String[] directives = { "script", };
private static final ScriptUtil.ValidAttribute[] scriptDvalidAttrs =
{
new ScriptUtil.ValidAttribute("import"),
new ScriptUtil.ValidAttribute("charset")};
public boolean accept(
ParseEventListener listener,
ScriptReader reader,
Parser parser)
throws ScriptException
{
String close;
String open;
if (reader.matches(OPEN_DIRECTIVE))
{
open = OPEN_DIRECTIVE;
close = CLOSE_DIRECTIVE;
}
else
return false;
Mark start = reader.mark();
reader.advance(open.length());
reader.skipSpaces();
// Check which directive it is.
String match = null;
for (int i = 0; i < directives.length; i++)
if (reader.matches(directives[i]))
{
match = directives[i];
break;
}
if (match == null)
throw new ScriptException(
reader.mark(),
sm.getString("script.error.invalid.directive"));
reader.advance(match.length());
// Parse the attr-val pairs.
Hashtable attrs = reader.parseTagAttributes();
if (match.equals("script"))
ScriptUtil.checkAttributes(
"Script directive",
attrs,
scriptDvalidAttrs,
start);
// Match close.
reader.skipSpaces();
if (!reader.matches(close))
throw new ScriptException(
reader.mark(),
sm.getString("script.error.unterminated", new Object[] { open }));
else
reader.advance(close.length());
Mark stop = reader.mark();
listener.handleDirective(match, start, stop, attrs);
return true;
}
}
static {
coreElements.addElement(new Directive());
}
//scriptlets
static final class Scriptlet implements CoreElement
{
private static final String OPEN_SCRIPTLET = "<%";
private static final String CLOSE_SCRIPTLET = "%>";
private static final ScriptUtil.ValidAttribute[] validAttributes = {
};
public boolean accept(
ParseEventListener listener,
ScriptReader reader,
Parser parser)
throws ScriptException
{
String close, open, end_open = null;
Hashtable attrs = null;
Mark start;
if (reader.matches(OPEN_SCRIPTLET))
{
open = OPEN_SCRIPTLET;
close = CLOSE_SCRIPTLET;
}
else
return false;
reader.advance(open.length());
start = reader.mark();
if (end_open != null)
{
attrs = reader.parseTagAttributes();
reader.skipSpaces();
if (!reader.matches(end_open))
throw new ScriptException(
reader.mark(),
sm.getString("script.error.unterminated"));
reader.advance(end_open.length());
reader.skipSpaces();
ScriptUtil.checkAttributes("Scriptlet", attrs, validAttributes, start);
}
Mark stop = reader.skipUntil(close);
if (stop == null)
throw new ScriptException(
reader.mark(),
sm.getString("script.error.unterminated", new Object[] { open }));
listener.handleScriptlet(start, stop, attrs);
return true;
}
}
static {
coreElements.addElement(new Scriptlet());
}
void flushCharData(Mark start, Mark stop) throws ScriptException
{
char[] array = caw.toCharArray();
if (array.length != 0) // Avoid unnecessary out.write("") statements...
{
listener.handleCharData(start, stop, caw.toCharArray());
}
caw = new CharArrayWriter();
}
public void parse() throws ScriptException
{
parse(null);
}
public void parse(String until) throws ScriptException
{
parse(until, null);
}
public void parse(String until, Class[] accept) throws ScriptException
{
boolean noscriptElement = false;
while (reader.hasMoreInput())
{
if (until != null && reader.matches(until))
return;
Enumeration e = coreElements.elements();
if (accept != null)
{
Vector v = new Vector();
while (e.hasMoreElements())
{
CoreElement c = (CoreElement) e.nextElement();
for (int i = 0; i < accept.length; i++)
if (c.getClass().equals(accept[i]))
v.addElement(c);
}
e = v.elements();
}
boolean accepted = false;
while (e.hasMoreElements())
{
CoreElement c = (CoreElement) e.nextElement();
Mark m = reader.mark();
if (c.accept(listener, reader, this))
{
accepted = true;
noscriptElement = false;
break;
}
}
if (!accepted)
{
// This is a hack. "reader.nextContent()" will just return
// after it sees "<" -- not necessarily a script element. Using
// a boolean we will ensure that tmplStart changes only when
// strictly necessary.
if (noscriptElement == false)
{
tmplStart = reader.mark();
noscriptElement = true;
}
String s = reader.nextContent();
tmplStop = reader.mark();
caw.write(s, 0, s.length());
}
}
flushCharData(tmplStart, tmplStop);
}
}