List<Handler> handlers = new ArrayList<Handler>();
TemplateReader reader = env.getReader();
TemplateParser parser = reader.getTemplateParser();
Handler parentHandler = null;
Stack<Handler> handlerStack = new Stack<Handler>();
LayoutElement parent = env.getParent();
// Skip whitespace...
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
int ch = -1;
// We now support 2 syntaxes:
// <!event type="beforeCreate">[handlers]</event>
// <!beforeCreate [handlers] />
// If "eventName" is event, look for type and the closing '>' before
// trying to parse the handlers.
boolean useBodyContent = false;
boolean createHandlerDefinitionOnLayoutDefinition = false;
if (eventName.equals("handler")) {
// We have a <handler id="foo"> tag...
createHandlerDefinitionOnLayoutDefinition = true;
useBodyContent = true;
// Read type="...", no other options are supported at this time
NameValuePair nvp = parser.getNVP(null);
if (!nvp.getName().equals("id")) {
throw new SyntaxException(
"When defining and event, you must supply the event type! "
+ "Found \"...event " + nvp.getName() + "\" instead.");
}
eventName = nvp.getValue().toString();
// Ensure the next character is '>'
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
ch = parser.nextChar();
if (ch != '>') {
throw new SyntaxException(
"Syntax error in event definition, found: '...handler id=\""
+ eventName + "\" " + ((char) ch)
+ "\'. Expected closing '>' for opening handler element.");
}
// Get ready to read the handlers now...
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
ch = parser.nextChar();
} else if (eventName.equals("event")) {
// We have the new syntax...
useBodyContent = true;
// Read type="...", no other options are supported at this time
NameValuePair nvp = parser.getNVP(null);
if (!nvp.getName().equals("type")) {
throw new SyntaxException(
"When defining and event, you must supply the event type! "
+ "Found \"...event " + nvp.getName() + "\" instead.");
}
eventName = nvp.getValue().toString();
// Ensure the next character is '>'
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
ch = parser.nextChar();
if (ch != '>') {
throw new SyntaxException(
"Syntax error in event definition, found: '...event type=\""
+ eventName + "\" " + ((char) ch)
+ "\'. Expected closing '>' for opening event element.");
}
// Get ready to read the handlers now...
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
ch = parser.nextChar();
} else {
// Make sure to read the first char for the old syntax...
ch = parser.nextChar();
}
// Read the Handler(s)...
while (ch != -1) {
if (useBodyContent) {
// If we're using the new format.... check for "</event>"
if (ch == '<') {
// Just unread the '<', framework will validate the rest
parser.unread('<');
break;
}
} else {
if ((ch == '/') || (ch == '>')) {
// We found the end in the case where the handlers are
// inside the tag (old syntax).
break;
}
}
// Check for {}'s
if ((ch == LEFT_CURLY) || (ch == RIGHT_CURLY)) {
if (ch == LEFT_CURLY) {
// We are defining child handlers
handlerStack.push(parentHandler);
parentHandler = handler;
} else {
// We are DONE defining child handlers
if (handlerStack.empty()) {
throw new SyntaxException("Encountered unmatched '"
+ RIGHT_CURLY + "' when parsing handlers for '"
+ eventName + "' event.");
}
parentHandler = handlerStack.pop();
}
// ';' or ',' characters may appear between handlers
parser.skipCommentsAndWhiteSpace(
TemplateParser.SIMPLE_WHITE_SPACE + ",;");
// We need to "continue" b/c we need to check next ch again
ch = parser.nextChar();
continue;
}
// Get Handler ID / Definition
parser.unread(ch);
// Read a Handler
handler = readHandler(parser, eventName, parent);
// Add the handler to the appropriate place
if (parentHandler == null) {
handlers.add(handler);
} else {
parentHandler.addChildHandler(handler);
}
// Look at the next character...
ch = parser.nextChar();
}
if (ch == -1) {
// Make sure we didn't get to the end of the file
throw new SyntaxException("Unexpected EOF encountered while "
+ "parsing handlers for event '" + eventName + "'!");
}
// Do some checks to make sure everything is good...
if (!handlerStack.empty()) {
throw new SyntaxException("Unmatched '" + LEFT_CURLY
+ "' when parsing handlers for '" + eventName
+ "' event.");
}
if (!useBodyContent) {
// Additional checks for old syntax...
if (ch == '>') {
throw new SyntaxException("Handlers for event '" + eventName
+ "' did not end with '/>' but instead ended with '>'!");
}
if (ch == '/') {
// Make sure we have a "/>"...
parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE);
ch = parser.nextChar();
if (ch != '>') {
throw new SyntaxException("Expected '/>' a end of '"
+ eventName + "' event. But found '/"
+ (char) ch + "'.");
}
reader.popTag(); // Get rid of this event tag from the Stack
ctx.endSpecial(env, eventName);
}
} else {
// We need to recurse in order for the end-tag code to properly
// close out the context and make everything run correctly...
// Process child LayoutElements (should be none)
reader.process(EVENT_PROCESSING_CONTEXT, parent,
LayoutElementUtil.isLayoutComponentChild(parent));
}
// Set the Handlers on the parent...
if (createHandlerDefinitionOnLayoutDefinition) {
HandlerDefinition def = new HandlerDefinition(eventName);
def.setChildHandlers(handlers);
parent.getLayoutDefinition().setHandlerDefinition(eventName, def);
} else {
parent.setHandlers(eventName, handlers);
}
}