/**
   * @param result
   * @param element
   * @param dataList
   */
  public void processRepeat(
      Node result, Element element, Iterable<?> dataList, Runnable onEachLoop) {
    if (dataList == null) {
      return;
    }

    // Compute list size
    int size = Iterables.size(dataList);

    if (size > 0) {
      // Save the initial EL state
      Map<String, ? extends Object> oldContext = templateContext.getContext();
      Object oldCur = templateContext.getCur();
      ValueExpression oldVarExpression = null;

      // Set the new Context variable.  Copy the old context to preserve
      // any existing "index" variable
      Map<String, Object> loopData = Maps.newHashMap(oldContext);
      loopData.put(PROPERTY_COUNT, size);
      templateContext.setContext(loopData);

      // TODO: This means that any loop with @var doesn't make the loop
      // variable available in the default expression context.
      // Update the specification to make this explicit.
      Attr varAttr = element.getAttributeNode(ATTRIBUTE_VAR);
      if (varAttr == null) {
        oldCur = templateContext.getCur();
      } else {
        oldVarExpression = elContext.getVariableMapper().resolveVariable(varAttr.getValue());
      }

      Attr indexVarAttr = element.getAttributeNode(ATTRIBUTE_INDEX);
      String indexVar = indexVarAttr == null ? PROPERTY_INDEX : indexVarAttr.getValue();

      int index = 0;
      for (Object data : dataList) {
        loopData.put(indexVar, index++);

        // Set up context for rendering inner node
        templateContext.setCur(data);
        if (varAttr != null) {
          ValueExpression varExpression = expressions.constant(data, Object.class);
          elContext.getVariableMapper().setVariable(varAttr.getValue(), varExpression);
        }

        onEachLoop.run();
      }

      // Restore EL state
      if (varAttr == null) {
        templateContext.setCur(oldCur);
      } else {
        elContext.getVariableMapper().setVariable(varAttr.getValue(), oldVarExpression);
      }

      templateContext.setContext(oldContext);
    }
  }
  @Before
  public void setUp() throws Exception {
    control = EasyMock.createStrictControl();
    preloader = control.createMock(PipelinedDataPreloader.class);
    preloaderService = new ConcurrentPreloaderService(Executors.newSingleThreadExecutor(), null);
    executor = new PipelineExecutor(preloader, preloaderService, Expressions.forTesting());

    context = new GadgetContext() {};
  }
 /**
  * Evaluates an expression within the scope of this processor's context.
  *
  * @param expression The String expression
  * @param type Expected result type
  * @param defaultValue Default value to return in case of error
  */
 public <T> T evaluate(String expression, Class<T> type, T defaultValue) {
   try {
     ValueExpression expr = expressions.parse(expression, type);
     Object result = expr.getValue(elContext);
     return type.cast(result);
   } catch (ELException e) {
     logger.log(
         Level.WARNING,
         "EL failure for gadget {0}: {1}",
         new Object[] {getTemplateContext().getGadget().getContext().getUrl(), e.getMessage()});
     return defaultValue;
   }
 }
  /**
   * Process an entire template.
   *
   * @param template the DOM template, typically a script element
   * @param templateContext a template context providing top-level variables
   * @param globals ELResolver providing global variables other than those in the templateContext
   * @return a document fragment with the resolved content
   */
  public DocumentFragment processTemplate(
      Element template, TemplateContext templateContext, ELResolver globals, TagRegistry registry) {

    this.registry = registry;
    this.templateContext = templateContext;
    this.elContext =
        expressions.newELContext(
            globals,
            new GadgetELResolver(templateContext.getGadget().getContext()),
            new TemplateELResolver(templateContext),
            new ElementELResolver());

    DocumentFragment result = template.getOwnerDocument().createDocumentFragment();
    processChildNodes(result, template);
    return result;
  }
  @Before
  public void setUp() throws Exception {
    expressions = Expressions.forTesting();
    variables = Maps.newHashMap();
    singletonElementHandler = new SingletonElementHandler();
    Set<TagHandler> handlers =
        ImmutableSet.<TagHandler>of(new TestTagHandler(), singletonElementHandler);
    registry = new DefaultTagRegistry(handlers);

    processor = new DefaultTemplateProcessor(expressions);
    resolver = new RootELResolver();
    parser = new NekoSimplifiedHtmlParser(new ParseModule.DOMImplementationProvider().get());
    context = new TemplateContext(new Gadget(), variables);

    variables.put("foo", new JSONObject("{ title: 'bar' }"));
    variables.put("user", new JSONObject("{ id: '101', name: { first: 'John', last: 'Doe' }}"));
    variables.put("toys", new JSONObject("{ list: [{name: 'Ball'}, {name: 'Car'}]}"));
    variables.put("countries", new JSONArray("['Ireland','France']"));
    variables.put(
        "xss",
        new JSONObject(
            "{ script: '<script>alert();</script>'," + "quote:'\"><script>alert();</script>'}"));
  }