All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jsftemplating.layout.template.EventParserCommand Maven / Gradle / Ivy

/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://jsftemplating.dev.java.net/cddl1.html or
 * jsftemplating/cddl1.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at jsftemplating/cddl1.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
 */
package com.sun.jsftemplating.layout.template;

import com.sun.jsftemplating.layout.LayoutDefinitionManager;
import com.sun.jsftemplating.layout.SyntaxException;
import com.sun.jsftemplating.layout.descriptors.LayoutElement;
import com.sun.jsftemplating.layout.descriptors.handler.Handler;
import com.sun.jsftemplating.layout.descriptors.handler.HandlerDefinition;
import com.sun.jsftemplating.layout.descriptors.handler.OutputTypeManager;
import com.sun.jsftemplating.util.LayoutElementUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;


/**
 *  

This {@link CustomParserCommand} implementation processes handlers for * an event.

*/ public class EventParserCommand implements CustomParserCommand { /** *

This method processes a "custom" command. These are commands that * start with a !. When this method receives control, the * name (i.e. the token after the '!' character) has * already been read. It is passed via the name * parameter.

* *

This implementation processes events and their handlers. 2 * syntaxes are supported:

* *
  • <event type="beforeCreate">handler1(input="foo" output="bar"); ... </event>
  • *
  • <!beforeCreate handler1(input="foo" output="bar"); ... />
* *

The first format should be preferred.

* *

The {@link ProcessingContext} and * {@link ProcessingContextEnvironment} are both available.

*/ public void process(ProcessingContext ctx, ProcessingContextEnvironment env, String eventName) throws IOException { Handler handler = null; List handlers = new ArrayList(); TemplateReader reader = env.getReader(); TemplateParser parser = reader.getTemplateParser(); Handler parentHandler = null; Stack handlerStack = new Stack(); LayoutElement parent = env.getParent(); // Skip whitespace... parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE); int ch = -1; // We now support 2 syntaxes: // [handlers] // // If "eventName" is event, look for type and the closing '>' before // trying to parse the handlers. boolean useBodyContent = false; 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 "" 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); // 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... parent.setHandlers(eventName, handlers); } /** *

This method parses and creates an individual * Handler.

*/ private Handler readHandler(TemplateParser parser, String eventName) throws IOException { String target = null; String defVal = null; NameValuePair nvp = null; HandlerDefinition def = null; String handlerId = parser.readToken(); def = LayoutDefinitionManager.getGlobalHandlerDefinition(handlerId); if (def == null) { throw new SyntaxException("Handler '" + handlerId + "' in event '" + eventName + "' is not declared! " + "Ensure the '@Handler' annotation has been defined " + "on the handler Java method, that it has been " + "compiled with the annotation processing tool, and " + "that the resulting" + " 'META-INF/jsftemplating/Handler.map' is located " + "in your classpath (you may need to do a clean " + "build)."); } // Create a Handler Handler handler = new Handler(def); // Get the default name Map inputs = def.getInputDefs(); // FIXME: Allow for HandlerDefs to declare their default input if (inputs.size() == 1) { defVal = inputs.keySet().toArray()[0].toString(); } // Get the outputs so we can see what outputs have been declared Map outputs = def.getOutputDefs(); // Ensure we have an opening parenthesis parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE); int ch = parser.nextChar(); if (ch != '(') { throw new SyntaxException("While processing '<!" + eventName + "...' the handler '" + handlerId + "' was missing the '(' character!"); } // Move to the first char inside the parenthesis parser.skipWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE); ch = parser.nextChar(); // We should not ignore '#' characters for 'if' (Issue #5) if ((ch != '#') || !handlerId.equals(IF_HANDLER)) { parser.unread(ch); parser.skipCommentsAndWhiteSpace(""); // Already skipped white ch = parser.nextChar(); } // Allow if() handlers to be more flexible... if (handlerId.equals(IF_HANDLER) && (ch != '\'') && (ch != '"') && (ch != 'c')) { // FIXME: check for "condition", otherwise expressions starting with 'c' will // FIXME: not parse correctly // We have an if() w/o a condition="" && w/o quotes... // Take the entire value inside the ()'s to be the expression parser.unread(ch); handler.setCondition(parser.readUntil(')', false).trim()); ch = ')'; } // Read NVP(s)... while ((ch != -1) && (ch != ')')) { // Read NVP parser.unread(ch); try { nvp = parser.getNVP(defVal); } catch (SyntaxException ex) { throw new SyntaxException("Unable to process handler '" + handlerId + "'!", ex); } parser.skipCommentsAndWhiteSpace( TemplateParser.SIMPLE_WHITE_SPACE + ",;"); ch = parser.nextChar(); // Store the NVP.. target = nvp.getTarget(); if (target != null) { // "old-style" OutputMapping (key=>$attribute{value}) // NOTE: 'value' must be a String for an OutputMapping handler.setOutputMapping( nvp.getName(), nvp.getValue().toString(), target); } else { // First check for special input value (condition) String name = nvp.getName(); if (name.equals(CONDITION_ATTRIBUTE) && ((inputs.get(CONDITION_ATTRIBUTE) == null) || (handlerId.equals(IF_HANDLER)))) { // We have a Handler condition, set it handler.setCondition(nvp.getValue().toString()); } else { // We still don't know if this is an input, output, or both // (EL is now supported as an output mapping: out="#{el}") boolean validIO = false; // We also check to see if the "old" output mapping was // used and DO NOT override it if it was. This is useful // if there are cases where an input and output share a // name and the user does not fix this... the old syntax // can reliably declare an output without a namespace // problem. if (outputs.containsKey(name) && (handler.getOutputValue(name) == null)) { // We have an Output... use 2 arg method for this // syntax (expects EL, or uses simple String for a // request attribute). handler.setOutputMapping( name, nvp.getValue().toString(), OutputTypeManager.EL_TYPE); validIO = true; } // Don't do "else" b/c it may be BOTH an input AND output if (inputs.containsKey(name)) { // We have an Input handler.setInputValue(name, nvp.getValue()); validIO = true; } if (!validIO) { throw new IllegalArgumentException( "Input or output named \"" + name + "\" was declared for handler \"" + handlerId + "\" in event \"" + eventName + "\", however, no such input or output exists!"); } } } } // ';' or ',' characters may appear between handlers parser.skipCommentsAndWhiteSpace(TemplateParser.SIMPLE_WHITE_SPACE + ",;"); // Return the Handler return handler; } /** *

This is the {@link ProcessingContext} for events. Currently does * nothing.

*/ protected static class EventProcessingContext extends BaseProcessingContext { } public static final String IF_HANDLER = "if"; public static final String CONDITION_ATTRIBUTE = "condition"; public static final ProcessingContext EVENT_PROCESSING_CONTEXT = new EventProcessingContext(); public static final char LEFT_CURLY = '{'; public static final char RIGHT_CURLY = '}'; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy