You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2016/11/03 11:28:26 UTC

svn commit: r1767871 [1/3] - in /myfaces/tobago/trunk: tobago-core/src/main/java/org/apache/myfaces/tobago/component/ tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/ tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/ t...

Author: lofwyr
Date: Thu Nov  3 11:28:25 2016
New Revision: 1767871

URL: http://svn.apache.org/viewvc?rev=1767871&view=rev
Log:
TOBAGO-1617: New tag <tc:event> to be similar to <f:ajax> and to replace <tc:command> in facets

Added:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedListStateWrapper.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedStateWrapper.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/DeltaStateHelper.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/EventBehavior.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIEvent.java
      - copied, changed from r1766668, myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIRow.java
      - copied, changed from r1765603, myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnEvent.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/EventTagDeclaration.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/RowTagDeclaration.java
      - copied, changed from r1765603, myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnEventTagDeclaration.java
    myfaces/tobago/trunk/tobago-core/src/test/java/org/apache/myfaces/tobago/component/ClientBehaviorsUnitTest.java
      - copied, changed from r1767843, myfaces/tobago/trunk/tobago-core/src/test/java/org/apache/myfaces/tobago/component/FacetsUnitTest.java
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/6000-event/
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/6000-event/event-input.xhtml
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/6000-event/event.xhtml
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/6000-event/progress.xhtml
      - copied, changed from r1766842, myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/020-output/50-progress/progress.xhtml
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/EventRenderer.java
      - copied, changed from r1766668, myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/CommandRendererBase.java
Removed:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ColumnEvent.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnEvent.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnEventTagDeclaration.java
Modified:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIInput.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPage.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIProgress.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
    myfaces/tobago/trunk/tobago-example/tobago-example-addressbook/src/main/webapp/addressbook/list.xhtml
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/ProgressController.java
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/30-event/sheet-column-event.xhtml
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/init.xhtml
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/AjaxClientBehaviorRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/Command.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/CommandMap.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/JsonUtils.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/CommandRendererBase.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/InRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PanelRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/ProgressRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectBooleanCheckboxRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectManyCheckboxRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectManyListboxRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectManyShuttleRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectOneChoiceRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectOneListboxRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SelectOneRadioRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/SheetRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/TextareaRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/TreeSelectRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/util/HtmlRendererUtils.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/util/RenderUtils.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago-sheet.js
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/test/java/org/apache/myfaces/tobago/renderkit/html/JsonUtilsUnitTest.java
    myfaces/tobago/trunk/tobago-tool/tobago-tool-apt/src/main/java/org/apache/myfaces/tobago/apt/processor/FacesConfigGenerator.java
    myfaces/tobago/trunk/tobago-tool/tobago-tool-apt/src/main/resources/org/apache/myfaces/tobago/apt/component.stg

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.component;
+
+public enum ClientBehaviors {
+
+  click,
+  change;
+
+  public static final String CLICK = "click";
+  public static final String CHANGE = "click";
+
+}

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java Thu Nov  3 11:28:25 2016
@@ -34,6 +34,7 @@ public enum RendererTypes {
   Command,
   Commands,
   Date,
+  Event,
   Figure,
   File,
   FlexLayout,
@@ -100,6 +101,7 @@ public enum RendererTypes {
   public static final String COLUMN_SELECTOR = "ColumnSelector";
   public static final String COMMAND = "Command";
   public static final String COMMANDS = "Commands";
+  public static final String EVENT = "Event";
   public static final String DATE = "Date";
   public static final String FIGURE = "Figure";
   public static final String FILE = "File";

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.facelets;
+
+import org.apache.myfaces.tobago.internal.behavior.EventBehavior;
+import org.apache.myfaces.tobago.component.Attributes;
+
+import javax.el.MethodExpression;
+import javax.faces.component.PartialStateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.component.behavior.AjaxBehavior;
+import javax.faces.component.behavior.ClientBehavior;
+import javax.faces.component.behavior.ClientBehaviorHolder;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.AjaxBehaviorEvent;
+import javax.faces.event.AjaxBehaviorListener;
+import javax.faces.view.BehaviorHolderAttachedObjectHandler;
+import javax.faces.view.facelets.ComponentConfig;
+import javax.faces.view.facelets.ComponentHandler;
+import javax.faces.view.facelets.FaceletContext;
+import javax.faces.view.facelets.TagAttribute;
+import javax.faces.view.facelets.TagAttributeException;
+import javax.faces.view.facelets.TagException;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This tag creates an instance of AjaxBehavior, and associates it with the nearest
+ * parent UIComponent that implements ClientBehaviorHolder interface. This tag can
+ * be used on single or composite components.
+ * <p>
+ * Unless otherwise specified, all attributes accept static values or EL expressions.
+ * </p>
+ * <p>
+ * According to the documentation, the tag handler implementing this tag should meet
+ * the following conditions:
+ * </p>
+ * <ul>
+ * <li>Since this tag attach objects to UIComponent instances, and those instances
+ * implements Behavior interface, this component should implement
+ * BehaviorHolderAttachedObjectHandler interface.</li>
+ * <li>f:ajax does not support binding property. In theory we should do something similar
+ * to f:convertDateTime tag does: extends from ConverterHandler and override setAttributes
+ * method, but in this case BehaviorTagHandlerDelegate has binding property defined, so
+ * if we extend from BehaviorHandler we add binding support to f:ajax.</li>
+ * <li>This tag works as a attached object handler, but note on the api there is no component
+ * to define a target for a behavior. See comment inside apply() method.</li>
+ * </ul>
+ *
+ * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
+ * @version $Revision: 1177714 $ $Date: 2011-09-30 15:51:51 +0000 (Fri, 30 Sep 2011) $
+ */
+public class EventHandler extends TobagoComponentHandler implements BehaviorHolderAttachedObjectHandler {
+
+  public final static Class<?>[] AJAX_BEHAVIOR_LISTENER_SIG = new Class<?>[]{AjaxBehaviorEvent.class};
+
+  private final TagAttribute _event;
+
+// todo (see original AjaxHandler impl)  private final boolean _wrapMode;
+
+  public EventHandler(ComponentConfig config) {
+    super(config);
+    _event = getAttribute(Attributes.event.getName());
+  }
+
+  public void apply(FaceletContext ctx, UIComponent parent)
+      throws IOException {
+
+    super.apply(ctx, parent);
+
+    //Apply only if we are creating a new component
+    if (!ComponentHandler.isNew(parent)) {
+      return;
+    }
+      if (parent instanceof ClientBehaviorHolder) {
+        //Apply this handler directly over the parent
+        applyAttachedObject(ctx.getFacesContext(), parent);
+//todo      } else if (UIComponent.isCompositeComponent(parent)) {
+//todo        FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
+        // It is supposed that for composite components, this tag should
+        // add itself as a target, but note that on whole api does not exists
+        // some tag that expose client behaviors as targets for composite
+        // components. In RI, there exists a tag called composite:clientBehavior,
+        // but does not appear on spec or javadoc, maybe because this could be
+        // understand as an implementation detail, after all there exists a key
+        // called AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY that could be
+        // used to create a tag outside jsf implementation to attach targets.
+//todo        mctx.addAttachedObjectHandler(parent, this);
+      } else {
+        throw new TagException(this.tag,
+            "Parent is not composite component or of type ClientBehaviorHolder, type is: "
+                + parent);
+      }
+  }
+
+  /**
+   * ViewDeclarationLanguage.retargetAttachedObjects uses it to check
+   * if the the target to be processed is applicable for this handler
+   */
+  public String getEventName() {
+    if (_event == null) {
+      return null;
+    } else {
+      return _event.getValue();
+    }
+  }
+
+  /**
+   * This method should create an AjaxBehavior object and attach it to the
+   * parent component.
+   * <p>
+   * Also, it should check if the parent can apply the selected AjaxBehavior
+   * to the selected component through ClientBehaviorHolder.getEventNames() or
+   * ClientBehaviorHolder.getDefaultEventName()
+   */
+  public void applyAttachedObject(FacesContext context, UIComponent parent) {
+    // Retrieve the current FaceletContext from FacesContext object
+    FaceletContext faceletContext = (FaceletContext) context
+        .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
+
+    // cast to a ClientBehaviorHolder
+    ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
+
+    String eventName = getEventName();
+    if (eventName == null) {
+      eventName = cvh.getDefaultEventName();
+      if (eventName == null) {
+          throw new TagAttributeException(_event, "eventName could not be defined for f:ajax tag with no wrap mode.");
+      }
+    } else if (!cvh.getEventNames().contains(eventName)) {
+        throw new TagAttributeException(_event, "event it is not a valid eventName defined for this component");
+    }
+
+    Map<String, List<ClientBehavior>> clientBehaviors = cvh.getClientBehaviors();
+
+    List<ClientBehavior> clientBehaviorList = clientBehaviors.get(eventName);
+    if (clientBehaviorList != null && !clientBehaviorList.isEmpty()) {
+      for (ClientBehavior cb : clientBehaviorList) {
+        if (cb instanceof AjaxBehavior) {
+          // The most inner one has been applied, so according to
+          // jsf 2.0 spec section 10.4.1.1 it is not necessary to apply
+          // this one, because the inner one has precendece over
+          // the outer one.
+          return;
+        }
+      }
+    }
+
+    EventBehavior ajaxBehavior = createBehavior(context);
+
+    cvh.addClientBehavior(eventName, ajaxBehavior);
+  }
+
+  protected EventBehavior createBehavior(FacesContext context) {
+    return (EventBehavior) context.getApplication().createBehavior(EventBehavior.BEHAVIOR_ID);
+  }
+
+  /**
+   * The documentation says this attribute should not be used since it is not
+   * taken into account. Instead, getEventName is used on
+   * ViewDeclarationLanguage.retargetAttachedObjects.
+   */
+  public String getFor() {
+    return null;
+  }
+
+  /**
+   * Wraps a method expression in a AjaxBehaviorListener
+   */
+  public final static class AjaxBehaviorListenerImpl implements
+      AjaxBehaviorListener, PartialStateHolder {
+    private MethodExpression _expr;
+    private boolean _transient;
+    private boolean _initialStateMarked;
+
+    public AjaxBehaviorListenerImpl() {
+    }
+
+    public AjaxBehaviorListenerImpl(MethodExpression expr) {
+      _expr = expr;
+    }
+
+    public void processAjaxBehavior(AjaxBehaviorEvent event)
+        throws AbortProcessingException {
+      _expr.invoke(FacesContext.getCurrentInstance().getELContext(),
+          new Object[]{event});
+    }
+
+    public boolean isTransient() {
+      return _transient;
+    }
+
+    public void restoreState(FacesContext context, Object state) {
+      if (state == null) {
+        return;
+      }
+      _expr = (MethodExpression) state;
+    }
+
+    public Object saveState(FacesContext context) {
+      if (initialStateMarked()) {
+        return null;
+      }
+      return _expr;
+    }
+
+    public void setTransient(boolean newTransientValue) {
+      _transient = newTransientValue;
+    }
+
+    public void clearInitialState() {
+      _initialStateMarked = false;
+    }
+
+    public boolean initialStateMarked() {
+      return _initialStateMarked;
+    }
+
+    public void markInitialState() {
+      _initialStateMarked = true;
+    }
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedListStateWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedListStateWrapper.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedListStateWrapper.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedListStateWrapper.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,23 @@
+package org.apache.myfaces.tobago.internal.behavior;
+
+import java.io.Serializable;
+import java.util.List;
+
+// todo: clean up (is a copy of MyFaces, but not all stuff is refactored)
+
+class AttachedListStateWrapper
+    implements Serializable
+{
+  private static final long serialVersionUID = -3958718149793179776L;
+  private List<Object> _wrappedStateList;
+
+  public AttachedListStateWrapper(List<Object> wrappedStateList)
+  {
+    _wrappedStateList = wrappedStateList;
+  }
+
+  public List<Object> getWrappedStateList()
+  {
+    return _wrappedStateList;
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedStateWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedStateWrapper.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedStateWrapper.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/AttachedStateWrapper.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,38 @@
+package org.apache.myfaces.tobago.internal.behavior;
+
+import java.io.Serializable;
+
+// todo: clean up (is a copy of MyFaces, but not all stuff is refactored)
+
+class AttachedStateWrapper implements Serializable
+{
+  private static final long serialVersionUID = 4948301780259917764L;
+  private Class<?> _class;
+  private Object _wrappedStateObject;
+
+  /**
+   * @param clazz
+   *            null means wrappedStateObject is a List of state objects
+   * @param wrappedStateObject
+   */
+  public AttachedStateWrapper(Class<?> clazz, Object wrappedStateObject)
+  {
+    if (wrappedStateObject != null && !(wrappedStateObject instanceof Serializable))
+    {
+      throw new IllegalArgumentException("Attached state for Object of type " + clazz + " (Class "
+          + wrappedStateObject.getClass().getName() + ") is not serializable");
+    }
+    _class = clazz;
+    _wrappedStateObject = wrappedStateObject;
+  }
+
+  public Class<?> getClazz()
+  {
+    return _class;
+  }
+
+  public Object getWrappedStateObject()
+  {
+    return _wrappedStateObject;
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/DeltaStateHelper.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/DeltaStateHelper.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/DeltaStateHelper.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/DeltaStateHelper.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,921 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.internal.behavior;
+
+import javax.el.ValueExpression;
+import javax.faces.component.StateHelper;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// todo: clean up (is a copy of MyFaces, but not all stuff is refactored)
+
+/**
+ * A delta enabled state holder implementing the StateHolder Interface.
+ * <p>
+ * Components implementing the PartalStateHolder interface have an initial state
+ * and delta states, the initial state is the one holding all root values
+ * and deltas store differences to the initial states
+ * </p>
+ * <p>
+ * For components not implementing partial state saving only the initial states are
+ * of importance, everything is stored and restored continously there
+ * </p>
+ * <p>
+ * The state helper seems to have three internal storage mechanisms:
+ * one being a list which stores plain values,
+ * one being a key value pair which stores key values in maps
+ * add serves the plain list type while put serves the
+ * key value type,
+ * the third is the value which has to be stored plainly as is!
+ * </p>
+ * In other words, this map can be seen as a composite map. It has two maps:
+ * initial state map and delta map.
+ * <p>
+ * If delta map is used (method component.initialStateMarked() ),
+ * base or initial state map cannot be changed, since all changes
+ * should be tracked on delta map.
+ * </p>
+ * <p>
+ * The intention of this class is just hold property values
+ * and do a clean separation between initial state and delta.
+ * </p>
+ * <p>
+ * The code from this class comes from a refactor of
+ * org.apache.myfaces.trinidad.bean.util.PropertyHashMap
+ * </p>
+ * <p>
+ * The context from this class comes and that should be taken into account
+ * is this:
+ * </p>
+ * <p>
+ * First request:
+ * </p>
+ * <ul>
+ *   <li> A new template is created (using
+ *   javax.faces.view.ViewDeclarationLanguage.buildView method)
+ *   and component.markInitialState is called from its related TagHandler classes
+ *  (see javax.faces.view.facelets.ComponentHandler ).
+ *   When this method is executed, the component tree was populated from the values
+ *   set in the facelet abstract syntax tree (or in other words composition of
+ *   facelets templates). </li>
+ *   <li> From this point all updates on the variables are considered "delta". </li>
+ *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
+ * </ul>
+ * <p>
+ * Second request (and next ones)
+ * </p>
+ * <ul>
+ *   <li> A new template is created and component.markInitialState is called from
+ *   its related TagHandler classes again. In this way, components like c:forEach
+ *   or c:if, that add or remove components could notify about this and handle
+ *   them properly (see javax.faces.view.StateManagementStrategy). Note that a
+ *   component restored using this method is no different as the same component
+ *   at the first request at the same time. </li>
+ *   <li> A call for restoreState is done, passing the delta as object value. If no
+ *   delta, the state is complete and no call is triggered. </li>
+ *   <li> Lifecycle occur, changing the necessary stuff. </li>
+ *   <li> SaveState, if initialStateMarked is true, only delta is saved. </li>
+ * </ul>
+ * <p>
+ * From the previous analysis, the following conclusions arise:
+ * <ul>
+ *   <li>This class only needs to keep track of delta changes, so when
+ *   restoreState/saveState is called, the right objects are passed.</li>
+ *   <li>UIComponent.clearInitialState is used to reset the partial
+ *   state holder to a non delta state, so the state to be saved by
+ *   saveState is no longer a delta instead is a full state. If a call
+ *   to clearInitialState occur it is not expected a call for
+ *   UIComponent.markInitialState occur on the current request.</li>
+ *   <li>The state is handled in the same way on UIData, so components
+ *   inside UIData share its state on all rows. There is no way to save
+ *   delta per row.</li>
+ *   <li>The map backed by method put(Serializable,String,Object) is
+ *   a replacement of UIComponentBase.attributesMap and UIComponent.bindings map.
+ *   Note that on jsf 1.2, instances saved on attributesMap should not be
+ *   StateHolder, but on jsf 2.0 it is possible to have it. PartialStateHolder
+ *   instances are not handled in this map, or in other words delta state is not
+ *   handled in this classes (markInitialState and clearInitialState is not propagated).</li>
+ *   <li>The list backed by method add(Serializable,Object) should be (is not) a
+ *   replacement of UIComponentBase.facesListeners, but note that StateHelper
+ *   does not implement PartialStateHolder, and facesListener could have instances
+ *   of that class that needs to be notified when UIComponent.markInitialState or
+ *   UIComponent.clearInitialState is called, or in other words facesListeners
+ *   should deal with PartialStateHolder instances.</li>
+ *   <li>The list backed by method add(Serializable,Object) is
+ *   a replacement of UIViewRoot.phaseListeners list. Note that instances of
+ *   PhaseListener are not expected to implement StateHolder or PartialStateHolder.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * NOTE: The current implementation of StateHelper on RI does not handle
+ * stateHolder values internally. To prevent problems when developers create
+ * custom components we should do this too. But anyway, the code that
+ * handle this case should be let here as comment, if some day this feature
+ * is provided. Note than stateHolder aware properties like converter,
+ * validator or listeners should deal with StateHolder or PartialStateHolder
+ * on component classes.
+ *
+ * </p>
+ *
+ * @author Werner Punz
+ * @author Leonardo Uribe (latest modification by $Author: bommel $)
+ * @version $Rev: 1187700 $ $Date: 2011-10-22 12:19:37 +0000 (Sat, 22 Oct 2011) $
+ */
+class DeltaStateHelper<A extends EventBehavior> implements StateHelper
+{
+
+  /**
+   * We need to hold a component instance because:
+   *
+   * - The component is the one who knows if we are on initial or delta mode
+   * - eval assume calls to component.ValueExpression
+   */
+  private A _target;
+
+  /**
+   * This map holds the full current state
+   */
+  private Map<Serializable, Object> _fullState;
+
+  /**
+   * This map only keep track of delta changes to be saved
+   */
+  private Map<Serializable, Object> _deltas;
+
+  /**
+   * This map keep track of StateHolder keys, to be saved when
+   * saveState is called.
+   */
+  //private Set<Serializable> _stateHolderKeys;
+
+  private boolean _transient = false;
+
+  public DeltaStateHelper(A target)
+  {
+    super();
+    this._target = target;
+    _fullState = new HashMap<Serializable, Object>();
+    _deltas = null;
+    //_stateHolderKeys = new HashSet<Serializable>();
+  }
+
+  /**
+   * Used to create delta map on demand
+   *
+   * @return
+   */
+  private boolean _createDeltas()
+  {
+    if (isInitialStateMarked())
+    {
+      if (_deltas == null)
+      {
+        _deltas = new HashMap<Serializable, Object>(2);
+      }
+      return true;
+    }
+
+    return false;
+  }
+
+  protected boolean isInitialStateMarked()
+  {
+    return _target.initialStateMarked();
+  }
+
+  public void add(Serializable key, Object value)
+  {
+    if (_createDeltas())
+    {
+      //Track delta case
+      Map<Object, Boolean> deltaListMapValues = (Map<Object, Boolean>) _deltas
+          .get(key);
+      if (deltaListMapValues == null)
+      {
+        deltaListMapValues = new DeltaStateHelper.InternalDeltaListMap<Object, Boolean>(
+            3);
+        _deltas.put(key, deltaListMapValues);
+      }
+      deltaListMapValues.put(value, Boolean.TRUE);
+    }
+
+    //Handle change on full map
+    List<Object> fullListValues = (List<Object>) _fullState.get(key);
+    if (fullListValues == null)
+    {
+      fullListValues = new DeltaStateHelper.InternalList<Object>(3);
+      _fullState.put(key, fullListValues);
+    }
+    fullListValues.add(value);
+  }
+
+  public Object eval(Serializable key)
+  {
+    Object returnValue = _fullState.get(key);
+    if (returnValue != null)
+    {
+      return returnValue;
+    }
+    ValueExpression expression = _target.getValueExpression(key
+        .toString());
+    if (expression != null)
+    {
+      return expression.getValue(FacesContext.getCurrentInstance()
+          .getELContext());
+    }
+    return null;
+  }
+
+  public Object eval(Serializable key, Object defaultValue)
+  {
+    Object returnValue = _fullState.get(key);
+    if (returnValue != null)
+    {
+      return returnValue;
+    }
+    ValueExpression expression = _target.getValueExpression(key
+        .toString());
+    if (expression != null)
+    {
+      return expression.getValue(FacesContext.getCurrentInstance()
+          .getELContext());
+    }
+    return defaultValue;
+  }
+
+  public Object get(Serializable key)
+  {
+    return _fullState.get(key);
+  }
+
+  public Object put(Serializable key, Object value)
+  {
+    Object returnValue = null;
+    if (_createDeltas())
+    {
+      if (_deltas.containsKey(key))
+      {
+        returnValue = _deltas.put(key, value);
+        _fullState.put(key, value);
+      }
+      else if (value == null && !_fullState.containsKey(key))
+      {
+        returnValue = null;
+      }
+      else
+      {
+        _deltas.put(key, value);
+        returnValue = _fullState.put(key, value);
+      }
+    }
+    else
+    {
+            /*
+            if (value instanceof StateHolder)
+            {
+                _stateHolderKeys.add(key);
+            }
+            */
+      returnValue = _fullState.put(key, value);
+    }
+    return returnValue;
+  }
+
+  public Object put(Serializable key, String mapKey, Object value)
+  {
+    boolean returnSet = false;
+    Object returnValue = null;
+    if (_createDeltas())
+    {
+      //Track delta case
+      Map<String, Object> mapValues = (Map<String, Object>) _deltas
+          .get(key);
+      if (mapValues == null)
+      {
+        mapValues = new DeltaStateHelper.InternalMap<String, Object>();
+        _deltas.put(key, mapValues);
+      }
+      if (mapValues.containsKey(mapKey))
+      {
+        returnValue = mapValues.put(mapKey, value);
+        returnSet = true;
+      }
+      else
+      {
+        mapValues.put(mapKey, value);
+      }
+    }
+
+    //Handle change on full map
+    Map<String, Object> mapValues = (Map<String, Object>) _fullState
+        .get(key);
+    if (mapValues == null)
+    {
+      mapValues = new DeltaStateHelper.InternalMap<String, Object>();
+      _fullState.put(key, mapValues);
+    }
+    if (returnSet)
+    {
+      mapValues.put(mapKey, value);
+    }
+    else
+    {
+      returnValue = mapValues.put(mapKey, value);
+    }
+    return returnValue;
+  }
+
+  public Object remove(Serializable key)
+  {
+    Object returnValue = null;
+    if (_createDeltas())
+    {
+      if (_deltas.containsKey(key))
+      {
+        // Keep track of the removed values using key/null pair on the delta map
+        returnValue = _deltas.put(key, null);
+        _fullState.remove(key);
+      }
+      else
+      {
+        // Keep track of the removed values using key/null pair on the delta map
+        _deltas.put(key, null);
+        returnValue = _fullState.remove(key);
+      }
+    }
+    else
+    {
+      returnValue = _fullState.remove(key);
+    }
+    return returnValue;
+  }
+
+  public Object remove(Serializable key, Object valueOrKey)
+  {
+    // Comment by lu4242 : The spec javadoc says if it is a Collection
+    // or Map deal with it. But the intention of this method is work
+    // with add(?,?) and put(?,?,?), this ones return instances of
+    // InternalMap and InternalList to prevent mixing, so to be
+    // consistent we'll cast to those classes here.
+
+    Object collectionOrMap = _fullState.get(key);
+    Object returnValue = null;
+    if (collectionOrMap instanceof DeltaStateHelper.InternalMap)
+    {
+      if (_createDeltas())
+      {
+        returnValue = _removeValueOrKeyFromMap(_deltas, key,
+            valueOrKey, true);
+        _removeValueOrKeyFromMap(_fullState, key, valueOrKey, false);
+      }
+      else
+      {
+        returnValue = _removeValueOrKeyFromMap(_fullState, key,
+            valueOrKey, false);
+      }
+    }
+    else if (collectionOrMap instanceof DeltaStateHelper.InternalList)
+    {
+      if (_createDeltas())
+      {
+        returnValue = _removeValueOrKeyFromCollectionDelta(_deltas,
+            key, valueOrKey);
+        _removeValueOrKeyFromCollection(_fullState, key, valueOrKey);
+      }
+      else
+      {
+        returnValue = _removeValueOrKeyFromCollection(_fullState, key,
+            valueOrKey);
+      }
+    }
+    return returnValue;
+  }
+
+  private static Object _removeValueOrKeyFromCollectionDelta(
+      Map<Serializable, Object> stateMap, Serializable key,
+      Object valueOrKey)
+  {
+    Object returnValue = null;
+    Map<Object, Boolean> c = (Map<Object, Boolean>) stateMap.get(key);
+    if (c != null)
+    {
+      if (c.containsKey(valueOrKey))
+      {
+        returnValue = valueOrKey;
+      }
+      c.put(valueOrKey, Boolean.FALSE);
+    }
+    return returnValue;
+  }
+
+  private static Object _removeValueOrKeyFromCollection(
+      Map<Serializable, Object> stateMap, Serializable key,
+      Object valueOrKey)
+  {
+    Object returnValue = null;
+    Collection c = (Collection) stateMap.get(key);
+    if (c != null)
+    {
+      if (c.remove(valueOrKey))
+      {
+        returnValue = valueOrKey;
+      }
+      if (c.isEmpty())
+      {
+        stateMap.remove(key);
+      }
+    }
+    return returnValue;
+  }
+
+  private static Object _removeValueOrKeyFromMap(
+      Map<Serializable, Object> stateMap, Serializable key,
+      Object valueOrKey, boolean delta)
+  {
+    if (valueOrKey == null)
+    {
+      return null;
+    }
+
+    Object returnValue = null;
+    Map<String, Object> map = (Map<String, Object>) stateMap.get(key);
+    if (map != null)
+    {
+      if (delta)
+      {
+        // Keep track of the removed values using key/null pair on the delta map
+        returnValue = map.put((String) valueOrKey, null);
+      }
+      else
+      {
+        returnValue = map.remove(valueOrKey);
+      }
+
+      if (map.isEmpty())
+      {
+        //stateMap.remove(key);
+        stateMap.put(key, null);
+      }
+    }
+    return returnValue;
+  }
+
+  public boolean isTransient()
+  {
+    return _transient;
+  }
+
+  /**
+   * Serializing cod
+   * the serialized data structure consists of key value pairs unless the value itself is an internal array
+   * or a map in case of an internal array or map the value itself is another array with its initial value
+   * myfaces.InternalArray, myfaces.internalMap
+   *
+   * the internal Array is then mapped to another array
+   *
+   * the internal Map again is then mapped to a map with key value pairs
+   *
+   *
+   */
+  public Object saveState(FacesContext context)
+  {
+    Map serializableMap = (isInitialStateMarked()) ? _deltas : _fullState;
+
+    if (serializableMap == null || serializableMap.size() == 0)
+    {
+      return null;
+    }
+
+        /*
+        int stateHolderKeyCount = 0;
+        if (isInitalStateMarked())
+        {
+            for (Iterator<Serializable> it = _stateHolderKeys.iterator(); it.hasNext();)
+            {
+                Serializable key = it.next();
+                if (!_deltas.containsKey(key))
+                {
+                    stateHolderKeyCount++;
+                }
+            }
+        }*/
+
+    Map.Entry<Serializable, Object> entry;
+    //entry == key, value, key, value
+    Object[] retArr = new Object[serializableMap.entrySet().size() * 2];
+    //Object[] retArr = new Object[serializableMap.entrySet().size() * 2 + stateHolderKeyCount];
+
+    Iterator<Map.Entry<Serializable, Object>> it = serializableMap
+        .entrySet().iterator();
+    int cnt = 0;
+    while (it.hasNext())
+    {
+      entry = it.next();
+      retArr[cnt] = entry.getKey();
+
+      Object value = entry.getValue();
+
+      // The condition in which the call to saveAttachedState
+      // is to handle List, StateHolder or non Serializable instances.
+      // we check it here, to prevent unnecessary calls.
+      if (value instanceof StateHolder ||
+          value instanceof List ||
+          !(value instanceof Serializable))
+      {
+        Object savedValue = saveAttachedState(context,
+            value);
+        retArr[cnt + 1] = savedValue;
+      }
+      else
+      {
+        retArr[cnt + 1] = value;
+      }
+      cnt += 2;
+    }
+
+        /*
+        if (isInitalStateMarked())
+        {
+            for (Iterator<Serializable> it2 = _stateHolderKeys.iterator(); it.hasNext();)
+            {
+                Serializable key = it2.next();
+                if (!_deltas.containsKey(key))
+                {
+                    retArr[cnt] = key;
+                    Object value = _fullState.get(key);
+                    if (value instanceof PartialStateHolder)
+                    {
+                        //Could contain delta, save it as _AttachedDeltaState
+                        PartialStateHolder holder = (PartialStateHolder) value;
+                        if (holder.isTransient())
+                        {
+                            retArr[cnt + 1] = null;
+                        }
+                        else
+                        {
+                            retArr[cnt + 1] = new _AttachedDeltaWrapper(value.getClass(), holder.saveState(context));
+                        }
+                    }
+                    else
+                    {
+                        //Save everything
+                        retArr[cnt + 1] = saveAttachedState(context, _fullState.get(key));
+                    }
+                    cnt += 2;
+                }
+            }
+        }
+        */
+    return retArr;
+  }
+
+  public void restoreState(FacesContext context, Object state)
+  {
+    if (state == null)
+      return;
+
+    Object[] serializedState = (Object[]) state;
+
+    if (!isInitialStateMarked() && !_fullState.isEmpty())
+    {
+      _fullState.clear();
+      if(_deltas != null)
+      {
+        _deltas.clear();
+      }
+    }
+
+    for (int cnt = 0; cnt < serializedState.length; cnt += 2)
+    {
+      Serializable key = (Serializable) serializedState[cnt];
+      Object savedValue = restoreAttachedState(context,
+          serializedState[cnt + 1]);
+
+      if (isInitialStateMarked())
+      {
+        if (savedValue instanceof DeltaStateHelper.InternalDeltaListMap)
+        {
+          for (Map.Entry<Object, Boolean> mapEntry : ((Map<Object, Boolean>) savedValue)
+              .entrySet())
+          {
+            boolean addOrRemove = mapEntry.getValue();
+            if (addOrRemove)
+            {
+              //add
+              this.add(key, mapEntry.getKey());
+            }
+            else
+            {
+              //remove
+              this.remove(key, mapEntry.getKey());
+            }
+          }
+        }
+        else if (savedValue instanceof DeltaStateHelper.InternalMap)
+        {
+          for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) savedValue)
+              .entrySet())
+          {
+            this.put(key, mapEntry.getKey(), mapEntry.getValue());
+          }
+        }
+                /*
+                else if (savedValue instanceof _AttachedDeltaWrapper)
+                {
+                    AttachedStateWrapper wrapper = (AttachedStateWrapper) savedValue;
+                    //Restore delta state
+                    ((PartialStateHolder)_fullState.get(key)).restoreState(context, wrapper.getWrappedStateObject());
+                    //Add this key as StateHolder key
+                    _stateHolderKeys.add(key);
+                }
+                */
+        else
+        {
+          put(key, savedValue);
+        }
+      }
+      else
+      {
+        put(key, savedValue);
+      }
+    }
+  }
+
+  public void setTransient(boolean transientValue)
+  {
+    _transient = transientValue;
+  }
+
+  //We use our own data structures just to make sure
+  //nothing gets mixed up internally
+  static class InternalMap<K, V> extends HashMap<K, V> implements StateHolder
+  {
+    public InternalMap()
+    {
+      super();
+    }
+
+    public InternalMap(int initialCapacity, float loadFactor)
+    {
+      super(initialCapacity, loadFactor);
+    }
+
+    public InternalMap(Map<? extends K, ? extends V> m)
+    {
+      super(m);
+    }
+
+    public InternalMap(int initialSize)
+    {
+      super(initialSize);
+    }
+
+    public boolean isTransient()
+    {
+      return false;
+    }
+
+    public void setTransient(boolean newTransientValue)
+    {
+      // No op
+    }
+
+    public void restoreState(FacesContext context, Object state)
+    {
+      Object[] listAsMap = (Object[]) state;
+      for (int cnt = 0; cnt < listAsMap.length; cnt += 2)
+      {
+        this.put((K) listAsMap[cnt], (V) UIComponentBase
+            .restoreAttachedState(context, listAsMap[cnt + 1]));
+      }
+    }
+
+    public Object saveState(FacesContext context)
+    {
+      int cnt = 0;
+      Object[] mapArr = new Object[this.size() * 2];
+      for (Map.Entry<K, V> entry : this.entrySet())
+      {
+        mapArr[cnt] = entry.getKey();
+        Object value = entry.getValue();
+
+        if (value instanceof StateHolder ||
+            value instanceof List ||
+            !(value instanceof Serializable))
+        {
+          mapArr[cnt + 1] = saveAttachedState(context, value);
+        }
+        else
+        {
+          mapArr[cnt + 1] = value;
+        }
+        cnt += 2;
+      }
+      return mapArr;
+    }
+  }
+
+  /**
+   * Map used to keep track of list changes
+   */
+  static class InternalDeltaListMap<K, V> extends DeltaStateHelper.InternalMap<K, V>
+  {
+
+    public InternalDeltaListMap()
+    {
+      super();
+    }
+
+    public InternalDeltaListMap(int initialCapacity, float loadFactor)
+    {
+      super(initialCapacity, loadFactor);
+    }
+
+    public InternalDeltaListMap(int initialSize)
+    {
+      super(initialSize);
+    }
+
+    public InternalDeltaListMap(Map<? extends K, ? extends V> m)
+    {
+      super(m);
+    }
+  }
+
+  static class InternalList<T> extends ArrayList<T> implements StateHolder
+  {
+    public InternalList()
+    {
+      super();
+    }
+
+    public InternalList(Collection<? extends T> c)
+    {
+      super(c);
+    }
+
+    public InternalList(int initialSize)
+    {
+      super(initialSize);
+    }
+
+    public boolean isTransient()
+    {
+      return false;
+    }
+
+    public void setTransient(boolean newTransientValue)
+    {
+    }
+
+    public void restoreState(FacesContext context, Object state)
+    {
+      Object[] listAsArr = (Object[]) state;
+      //since all other options would mean dual iteration
+      //we have to do it the hard way
+      for (Object elem : listAsArr)
+      {
+        add((T) restoreAttachedState(context, elem));
+      }
+    }
+
+    public Object saveState(FacesContext context)
+    {
+      Object[] values = new Object[size()];
+      for (int i = 0; i < size(); i++)
+      {
+        Object value = get(i);
+
+        if (value instanceof StateHolder ||
+            value instanceof List ||
+            !(value instanceof Serializable))
+        {
+          values[i] = saveAttachedState(context, value);
+        }
+        else
+        {
+          values[i] = value;
+        }
+      }
+      return values;
+    }
+  }
+
+  private static Object saveAttachedState(FacesContext context, Object attachedObject)
+  {
+    if (context == null)
+    {
+      throw new NullPointerException ("context");
+    }
+
+    if (attachedObject == null)
+      return null;
+    // StateHolder interface should take precedence over
+    // List children
+    if (attachedObject instanceof StateHolder)
+    {
+      StateHolder holder = (StateHolder) attachedObject;
+      if (holder.isTransient())
+      {
+        return null;
+      }
+
+      return new AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
+    }
+    else if (attachedObject instanceof List)
+    {
+      List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
+      for (Object item : (List<?>) attachedObject)
+      {
+        if (item != null)
+        {
+          lst.add(saveAttachedState(context, item));
+        }
+      }
+
+      return new AttachedListStateWrapper(lst);
+    }
+    else if (attachedObject instanceof Serializable)
+    {
+      return attachedObject;
+    }
+    else
+    {
+      return new AttachedStateWrapper(attachedObject.getClass(), null);
+    }
+  }
+
+  private static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
+  {
+    if (context == null)
+      throw new NullPointerException("context");
+    if (stateObj == null)
+      return null;
+    if (stateObj instanceof AttachedListStateWrapper)
+    {
+      List<Object> lst = ((AttachedListStateWrapper) stateObj).getWrappedStateList();
+      List<Object> restoredList = new ArrayList<Object>(lst.size());
+      for (Object item : lst)
+      {
+        restoredList.add(restoreAttachedState(context, item));
+      }
+      return restoredList;
+    }
+    else if (stateObj instanceof AttachedStateWrapper)
+    {
+      Class<?> clazz = ((AttachedStateWrapper) stateObj).getClazz();
+      Object restoredObject;
+      try
+      {
+        restoredObject = clazz.newInstance();
+      }
+      catch (InstantiationException e)
+      {
+        throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
+            + " (missing no-args constructor?)", e);
+      }
+      catch (IllegalAccessException e)
+      {
+        throw new RuntimeException(e);
+      }
+      if (restoredObject instanceof StateHolder)
+      {
+        AttachedStateWrapper wrapper = (AttachedStateWrapper) stateObj;
+        Object wrappedState = wrapper.getWrappedStateObject();
+
+        StateHolder holder = (StateHolder) restoredObject;
+        holder.restoreState(context, wrappedState);
+      }
+      return restoredObject;
+    }
+    else
+    {
+      return stateObj;
+    }
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/EventBehavior.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/EventBehavior.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/EventBehavior.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/behavior/EventBehavior.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.internal.behavior;
+
+import javax.el.ValueExpression;
+import javax.faces.component.StateHelper;
+import javax.faces.component.behavior.ClientBehaviorBase;
+import javax.faces.component.behavior.ClientBehaviorHint;
+import javax.faces.component.behavior.FacesBehavior;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AjaxBehaviorListener;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.myfaces.tobago.internal.behavior.EventBehavior.BEHAVIOR_ID;
+
+// todo: clean up (is a copy of MyFaces, but not all stuff is refactored)
+
+@FacesBehavior(value = BEHAVIOR_ID)
+public class EventBehavior extends ClientBehaviorBase
+{
+
+  /**
+   * not needed anymore but enforced by the spec
+   * theoretically a
+   * @FacesBehavior(value = "javax.faces.behavior.Ajax")
+   * could do it
+   */
+  public static final String BEHAVIOR_ID = "org.apache.myfaces.tobago.behavior.Event";
+
+  private static final String ATTR_EXECUTE = "execute";
+  private static final String ATTR_ON_ERROR = "onerror";
+  private static final String ATTR_ON_EVENT = "onevent";
+  private static final String ATTR_RENDER = "render";
+  private static final String ATTR_DISABLED = "disabled";
+  private static final String ATTR_IMMEDIATE = "immediate";
+
+  /**
+   * special render and execute targets
+   */
+  private static final String VAL_FORM = "@form";
+  private static final String VAL_ALL = "@all";
+  private static final String VAL_THIS = "@this";
+  private static final String VAL_NONE = "@none";
+
+  private static final Collection<String> VAL_FORM_LIST = Collections.singletonList(VAL_FORM);
+  private static final Collection<String> VAL_ALL_LIST = Collections.singletonList(VAL_ALL);
+  private static final Collection<String> VAL_THIS_LIST = Collections.singletonList(VAL_THIS);
+  private static final Collection<String> VAL_NONE_LIST = Collections.singletonList(VAL_NONE);
+
+  //To enable delta state saving we need this one
+  private DeltaStateHelper<EventBehavior> _stateHelper = null;
+
+  //private Map<String, ValueExpression> _valueExpressions
+  //        = new HashMap<String, ValueExpression>();
+
+  public EventBehavior()
+  {
+    super();
+  }
+
+  public void addAjaxBehaviorListener(AjaxBehaviorListener listener)
+  {
+    super.addBehaviorListener(listener);
+  }
+
+  public void removeAjaxBehaviorListener(AjaxBehaviorListener listener)
+  {
+    removeBehaviorListener(listener);
+  }
+
+  public Collection<String> getExecute()
+  {
+    // we have to evaluate the real value in this method,
+    // because the value of the ValueExpression might
+    // change (almost sure it does!)
+    return evalForCollection(ATTR_EXECUTE);
+  }
+
+  public void setExecute(Collection<String> execute)
+  {
+    getStateHelper().put(ATTR_EXECUTE, execute);
+  }
+
+  public String getOnerror()
+  {
+    return (String) getStateHelper().eval(ATTR_ON_ERROR);
+  }
+
+  public void setOnerror(String onError)
+  {
+    getStateHelper().put(ATTR_ON_ERROR, onError);
+  }
+
+  public String getOnevent()
+  {
+    return (String) getStateHelper().eval(ATTR_ON_EVENT);
+  }
+
+  public void setOnevent(String onEvent)
+  {
+    getStateHelper().put(ATTR_ON_EVENT, onEvent);
+  }
+
+  public Collection<String> getRender()
+  {
+    // we have to evaluate the real value in this method,
+    // because the value of the ValueExpression might
+    // change (almost sure it does!)
+    return evalForCollection(ATTR_RENDER);
+  }
+
+  public void setRender(Collection<String> render)
+  {
+    getStateHelper().put(ATTR_RENDER, render);
+  }
+
+  @SuppressWarnings("unchecked")
+  public ValueExpression getValueExpression(String name)
+  {
+    //return getValueExpressionMap().get(name);
+    if (name == null)
+    {
+      throw new NullPointerException("name can not be null");
+    }
+
+    Map<String,Object> bindings = (Map<String,Object>) getStateHelper().
+        get(EventBehavior.PropertyKeys.bindings);
+    if (bindings != null)
+    {
+      return (ValueExpression) bindings.get(name);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public void setValueExpression(String name, ValueExpression expression)
+  {
+        /*
+        if (item == null)
+        {
+            getValueExpressionMap().remove(name);
+            getStateHelper().remove(name);
+        }
+        else
+        {
+            getValueExpressionMap().put(name, item);
+        }
+        */
+    if (name == null)
+    {
+      throw new NullPointerException("name");
+    }
+
+    if (expression == null)
+    {
+      getStateHelper().remove(EventBehavior.PropertyKeys.bindings, name);
+    }
+    else
+    {
+      getStateHelper().put(EventBehavior.PropertyKeys.bindings, name, expression);
+    }
+  }
+
+  public boolean isDisabled()
+  {
+    Boolean retVal = (Boolean) getStateHelper().eval(ATTR_DISABLED);
+    retVal = (retVal == null) ? false : retVal;
+    return retVal;
+  }
+
+  public void setDisabled(boolean disabled)
+  {
+    getStateHelper().put(ATTR_DISABLED, disabled);
+  }
+
+  public boolean isImmediate()
+  {
+    Boolean retVal = (Boolean) getStateHelper().eval(ATTR_IMMEDIATE);
+    retVal = (retVal == null) ? false : retVal;
+    return retVal;
+  }
+
+  public void setImmediate(boolean immediate)
+  {
+    getStateHelper().put(ATTR_IMMEDIATE, immediate);
+  }
+
+  public boolean isImmediateSet()
+  {
+    return (getStateHelper().get(ATTR_IMMEDIATE) != null) ||
+        (getValueExpression(ATTR_IMMEDIATE) != null);
+  }
+
+  @Override
+  public Set<ClientBehaviorHint> getHints()
+  {
+    return EnumSet.of(ClientBehaviorHint.SUBMITTING);
+  }
+
+  @Override
+  public String getRendererType()
+  {
+    return BEHAVIOR_ID;
+  }
+
+  @Override
+  public void restoreState(FacesContext facesContext, Object o)
+  {
+    if (o == null)
+    {
+      return;
+    }
+    Object[] values = (Object[]) o;
+    if (values[0] != null)
+    {
+      super.restoreState(facesContext, values[0]);
+    }
+    getStateHelper().restoreState(facesContext, values[1]);
+  }
+
+  private StateHelper getStateHelper()
+  {
+    return getStateHelper(true);
+  }
+
+  /**
+   * returns a delta state saving enabled state helper
+   * for the current component
+   * @param create if true a state helper is created if not already existing
+   * @return an implementation of the StateHelper interface or null if none exists and create is set to false
+   */
+  private StateHelper getStateHelper(boolean create)
+  {
+    if(_stateHelper != null)
+    {
+      return _stateHelper;
+    }
+    if(create)
+    {
+      _stateHelper = new DeltaStateHelper<EventBehavior>(this);
+    }
+    return _stateHelper;
+  }
+
+  @Override
+  public Object saveState(FacesContext facesContext)
+  {
+    if (initialStateMarked())
+    {
+      Object parentSaved = super.saveState(facesContext);
+      Object stateHelperSaved = null;
+      StateHelper stateHelper = getStateHelper(false);
+      if (stateHelper != null)
+      {
+        stateHelperSaved = stateHelper.saveState(facesContext);
+      }
+
+      if (parentSaved == null && stateHelperSaved == null)
+      {
+        //No values
+        return null;
+      }
+      return new Object[]{parentSaved, stateHelperSaved};
+    }
+    else
+    {
+      Object[] values = new Object[2];
+      values[0] = super.saveState(facesContext);
+      StateHelper stateHelper = getStateHelper(false);
+      if (stateHelper != null)
+      {
+        values[1] = stateHelper.saveState(facesContext);
+      }
+      return values;
+    }
+  }
+
+  //private Map<String, ValueExpression> getValueExpressionMap()
+  //{
+  //    return _valueExpressions;
+  //}
+
+  /**
+   * Invokes eval on the getStateHelper() and tries to get a
+   * Collection out of the result.
+   * @param attributeName
+   * @return
+   */
+  @SuppressWarnings("unchecked")
+  private Collection<String> evalForCollection(String attributeName)
+  {
+    Object value = getStateHelper().eval(attributeName);
+    if (value == null)
+    {
+      return Collections.<String>emptyList();
+    }
+    else if (value instanceof Collection)
+    {
+      return (Collection<String>) value;
+    }
+    else if (value instanceof String)
+    {
+      return getCollectionFromSpaceSplitString((String) value);
+    }
+    else
+    {
+      throw new IllegalArgumentException("Type " + value.getClass()
+          + " not supported for attribute " + attributeName);
+    }
+  }
+
+  /**
+   * Splits the String based on spaces and returns the
+   * resulting Strings as Collection.
+   * @param stringValue
+   * @return
+   */
+  private Collection<String> getCollectionFromSpaceSplitString(String stringValue)
+  {
+    //@special handling for @all, @none, @form and @this
+    if (stringValue.equals(VAL_FORM))
+    {
+      return VAL_FORM_LIST;
+    }
+    else if (stringValue.equals(VAL_ALL))
+    {
+      return VAL_ALL_LIST;
+    }
+    else if (stringValue.equals(VAL_NONE))
+    {
+      return VAL_NONE_LIST;
+    }
+    else if (stringValue.equals(VAL_THIS))
+    {
+      return VAL_THIS_LIST;
+    }
+
+    // not one of the "normal" values - split it and return the Collection
+    String[] arrValue = stringValue.split(" ");
+    return Arrays.asList(arrValue);
+  }
+
+  private enum PropertyKeys
+  {
+    bindings,
+  }
+}

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java Thu Nov  3 11:28:25 2016
@@ -21,32 +21,18 @@ package org.apache.myfaces.tobago.intern
 
 import org.apache.myfaces.tobago.component.SupportsAccessKey;
 import org.apache.myfaces.tobago.component.Visual;
-import org.apache.myfaces.tobago.event.CollapsibleActionListener;
-import org.apache.myfaces.tobago.internal.util.AuthorizationHelper;
-import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.el.MethodExpression;
 import javax.faces.component.UICommand;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIInput;
 import javax.faces.component.behavior.ClientBehaviorHolder;
-import javax.faces.context.FacesContext;
-import javax.faces.event.ComponentSystemEvent;
-import javax.faces.event.ComponentSystemEventListener;
-import javax.faces.event.FacesEvent;
-import javax.faces.event.ListenerFor;
-import javax.faces.event.PhaseId;
-import javax.faces.event.PostAddToViewEvent;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
 
-@ListenerFor(systemEventClass = PostAddToViewEvent.class)
-public abstract class AbstractUICommand extends UICommand
-    implements SupportsAccessKey, Visual, ClientBehaviorHolder, ComponentSystemEventListener {
+public abstract class AbstractUICommand extends AbstractUICommandBase
+    implements SupportsAccessKey, Visual, ClientBehaviorHolder {
 
   private static final Logger LOG = LoggerFactory.getLogger(AbstractUICommand.class);
 
@@ -60,57 +46,6 @@ public abstract class AbstractUICommand
   // todo: transient
   private Boolean parentOfCommands;
 
-  @Override
-  public void processEvent(ComponentSystemEvent event) {
-    super.processEvent(event);
-
-    if (event instanceof PostAddToViewEvent) {
-      final List<AbstractUIOperation> list = ComponentUtils.findDescendantList(this, AbstractUIOperation.class);
-      for (AbstractUIOperation operation : list) {
-        addActionListener(new CollapsibleActionListener(operation.getFor()));
-      }
-    }
-  }
-
-  @Override
-  public void processDecodes(final FacesContext context) {
-    if (context == null) {
-      throw new NullPointerException();
-    }
-
-    // Skip processing if our rendered flag is false
-    if (!isRendered()) {
-      return;
-    }
-
-    // Process this component itself
-    try {
-      decode(context);
-    } catch (final RuntimeException e) {
-      context.renderResponse();
-      throw e;
-    }
-
-    final Iterator kids = getFacetsAndChildren();
-    while (kids.hasNext()) {
-      final UIComponent kid = (UIComponent) kids.next();
-      kid.processDecodes(context);
-    }
-  }
-
-  @Override
-  public void queueEvent(final FacesEvent facesEvent) {
-    // fix for TOBAGO-262
-    super.queueEvent(facesEvent);
-    if (this == facesEvent.getSource()) {
-      if (isImmediate()) {
-        facesEvent.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
-      } else {
-        facesEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
-      }
-    }
-  }
-
   public boolean isParentOfCommands() {
     if (parentOfCommands == null) {
       parentOfCommands = false;
@@ -124,37 +59,6 @@ public abstract class AbstractUICommand
     return parentOfCommands;
   }
 
-  /**
-   Flag indicating that this element is disabled.
-   <br>Default: <code>false</code>
-   */
-  public boolean isDisabled() {
-
-    final FacesContext facesContext = getFacesContext();
-    // todo: get from configuration tobago-config.xml
-    if (true) {
-      final AuthorizationHelper authorizationHelper = AuthorizationHelper.getInstance(facesContext);
-      final MethodExpression actionExpression = getActionExpression();
-      if (actionExpression != null) {
-        final boolean authorized =
-            authorizationHelper.isAuthorized(facesContext, actionExpression.getExpressionString());
-        if (!authorized) {
-          return true;
-        }
-      }
-    }
-
-    Boolean bool = (Boolean) getStateHelper().eval(PropertyKeys.disabled);
-    if (bool != null) {
-      return bool;
-    }
-    return false;
-  }
-
-  public void setDisabled(boolean disabled) {
-    getStateHelper().put(PropertyKeys.disabled, disabled);
-  }
-
   // todo generate
   @Override
   public String getDefaultEventName() {
@@ -169,18 +73,4 @@ public abstract class AbstractUICommand
 
   @Override
   public abstract String getLabel();
-
-  public abstract String getLink();
-
-  public abstract String getTarget();
-
-  public abstract boolean isTransition();
-
-  public abstract boolean isOmit();
-
-  public abstract void setOmit(boolean omit);
-
-  public abstract String getTip();
-
-  public abstract String getConfirmation();
 }

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java?rev=1767871&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java Thu Nov  3 11:28:25 2016
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.internal.component;
+
+import org.apache.myfaces.tobago.event.CollapsibleActionListener;
+import org.apache.myfaces.tobago.internal.util.AuthorizationHelper;
+import org.apache.myfaces.tobago.util.ComponentUtils;
+
+import javax.el.MethodExpression;
+import javax.faces.component.UICommand;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.event.FacesEvent;
+import javax.faces.event.ListenerFor;
+import javax.faces.event.PhaseId;
+import javax.faces.event.PostAddToViewEvent;
+import java.util.Iterator;
+import java.util.List;
+
+@ListenerFor(systemEventClass = PostAddToViewEvent.class)
+public abstract class AbstractUICommandBase extends UICommand
+    implements ComponentSystemEventListener {
+
+  @Override
+  public void processEvent(ComponentSystemEvent event) {
+    super.processEvent(event);
+
+    if (event instanceof PostAddToViewEvent) {
+      final List<AbstractUIOperation> list = ComponentUtils.findDescendantList(this, AbstractUIOperation.class);
+      for (AbstractUIOperation operation : list) {
+        addActionListener(new CollapsibleActionListener(operation.getFor()));
+      }
+    }
+  }
+
+  @Override
+  public void processDecodes(final FacesContext context) {
+    // Skip processing if our rendered flag is false
+    if (!isRendered()) {
+      return;
+    }
+
+    // Process this component itself
+    try {
+      decode(context);
+    } catch (final RuntimeException e) {
+      context.renderResponse();
+      throw e;
+    }
+
+    final Iterator kids = getFacetsAndChildren();
+    while (kids.hasNext()) {
+      final UIComponent kid = (UIComponent) kids.next();
+      kid.processDecodes(context);
+    }
+  }
+
+  @Override
+  public void queueEvent(final FacesEvent facesEvent) {
+    // fix for TOBAGO-262
+    super.queueEvent(facesEvent);
+    if (this == facesEvent.getSource()) {
+      if (isImmediate()) {
+        facesEvent.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+      } else {
+        facesEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
+      }
+    }
+  }
+
+  /**
+   Flag indicating that this element is disabled.
+   <br>Default: <code>false</code>
+   */
+  public boolean isDisabled() {
+
+    final FacesContext facesContext = getFacesContext();
+    // todo: get from configuration tobago-config.xml
+    if (true) {
+      final AuthorizationHelper authorizationHelper = AuthorizationHelper.getInstance(facesContext);
+      final MethodExpression actionExpression = getActionExpression();
+      if (actionExpression != null) {
+        final boolean authorized =
+            authorizationHelper.isAuthorized(facesContext, actionExpression.getExpressionString());
+        if (!authorized) {
+          return true;
+        }
+      }
+    }
+
+    Boolean bool = (Boolean) getStateHelper().eval(AbstractUICommand.PropertyKeys.disabled);
+    if (bool != null) {
+      return bool;
+    }
+    return false;
+  }
+
+  public void setDisabled(boolean disabled) {
+    getStateHelper().put(AbstractUICommand.PropertyKeys.disabled, disabled);
+  }
+
+  public abstract String getTarget();
+
+  public abstract boolean isTransition();
+
+  public abstract boolean isOmit();
+
+  public abstract void setOmit(boolean omit);
+
+  public abstract String getConfirmation();
+
+  public abstract String getLink();
+}

Copied: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIEvent.java (from r1766668, myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java)
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIEvent.java?p2=myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIEvent.java&p1=myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java&r1=1766668&r2=1767871&rev=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommand.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIEvent.java Thu Nov  3 11:28:25 2016
@@ -19,163 +19,10 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
-import org.apache.myfaces.tobago.component.OnComponentPopulated;
-import org.apache.myfaces.tobago.component.SupportsAccessKey;
-import org.apache.myfaces.tobago.component.Visual;
-import org.apache.myfaces.tobago.event.CollapsibleActionListener;
-import org.apache.myfaces.tobago.internal.util.AuthorizationHelper;
-import org.apache.myfaces.tobago.util.ComponentUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.myfaces.tobago.component.ClientBehaviors;
 
-import javax.el.MethodExpression;
-import javax.faces.component.UICommand;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIInput;
-import javax.faces.component.behavior.ClientBehaviorHolder;
-import javax.faces.context.FacesContext;
-import javax.faces.event.FacesEvent;
-import javax.faces.event.PhaseId;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+public abstract class AbstractUIEvent extends AbstractUICommandBase {
 
-public abstract class AbstractUICommand extends UICommand
-    implements SupportsAccessKey, OnComponentPopulated, Visual, ClientBehaviorHolder {
+  public abstract ClientBehaviors getEvent();
 
-  private static final Logger LOG = LoggerFactory.getLogger(AbstractUICommand.class);
-
-  // todo generate
-  private static final Collection<String> EVENT_NAMES = Arrays.asList("click", "change");
-
-  enum PropertyKeys {
-    disabled,
-  }
-
-  // todo: transient
-  private Boolean parentOfCommands;
-
-  @Override
-  public void onComponentPopulated(final FacesContext facesContext, final UIComponent parent) {
-
-    final List<AbstractUIOperation> list = ComponentUtils.findDescendantList(this, AbstractUIOperation.class);
-    for (AbstractUIOperation operation : list) {
-      addActionListener(new CollapsibleActionListener(operation.getFor()));
-    }
-  }
-
-  @Override
-  public void processDecodes(final FacesContext context) {
-    if (context == null) {
-      throw new NullPointerException();
-    }
-
-    // Skip processing if our rendered flag is false
-    if (!isRendered()) {
-      return;
-    }
-
-    // Process this component itself
-    try {
-      decode(context);
-    } catch (final RuntimeException e) {
-      context.renderResponse();
-      throw e;
-    }
-
-    final Iterator kids = getFacetsAndChildren();
-    while (kids.hasNext()) {
-      final UIComponent kid = (UIComponent) kids.next();
-      kid.processDecodes(context);
-    }
-  }
-
-  @Override
-  public void queueEvent(final FacesEvent facesEvent) {
-    // fix for TOBAGO-262
-    super.queueEvent(facesEvent);
-    if (this == facesEvent.getSource()) {
-      if (isImmediate()) {
-        facesEvent.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
-      } else {
-        facesEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
-      }
-    }
-  }
-
-  public boolean isParentOfCommands() {
-    if (parentOfCommands == null) {
-      parentOfCommands = false;
-      for (UIComponent child : getChildren()) {
-        if (child instanceof UICommand || child instanceof UIInput) {
-          parentOfCommands = true;
-          break;
-        }
-      }
-    }
-    return parentOfCommands;
-  }
-
-  /**
-   Flag indicating that this element is disabled.
-   <br>Default: <code>false</code>
-   */
-  public boolean isDisabled() {
-
-    final FacesContext facesContext = getFacesContext();
-    // todo: get from configuration tobago-config.xml
-    if (true) {
-      final AuthorizationHelper authorizationHelper = AuthorizationHelper.getInstance(facesContext);
-      final MethodExpression actionExpression = getActionExpression();
-      if (actionExpression != null) {
-        final boolean authorized =
-            authorizationHelper.isAuthorized(facesContext, actionExpression.getExpressionString());
-        if (!authorized) {
-          return true;
-        }
-      }
-    }
-
-    Boolean bool = (Boolean) getStateHelper().eval(PropertyKeys.disabled);
-    if (bool != null) {
-      return bool;
-    }
-    return false;
-  }
-
-  public void setDisabled(boolean disabled) {
-    getStateHelper().put(PropertyKeys.disabled, disabled);
-  }
-
-  // todo generate
-  @Override
-  public String getDefaultEventName() {
-    return "click";
-  }
-
-  // todo generate
-  @Override
-  public Collection<String> getEventNames() {
-    return EVENT_NAMES;
-  }
-
-  @Override
-  public abstract String getLabel();
-
-  public abstract String getLink();
-
-  public abstract String getTarget();
-
-  public abstract boolean isTransition();
-
-  public abstract boolean isOmit();
-
-  public abstract void setOmit(boolean omit);
-
-  public abstract String getTip();
-
-  public abstract String getConfirmation();
-
-//  public abstract Integer getTabIndex();
 }

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIInput.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIInput.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIInput.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIInput.java Thu Nov  3 11:28:25 2016
@@ -34,7 +34,7 @@ public abstract class AbstractUIInput ex
     implements SupportsAccessKey, SupportsLabelLayout, Visual, ClientBehaviorHolder, SupportFieldId {
 
   // todo generate
-  private static final Collection<String> EVENT_NAMES = Arrays.asList("change");
+  private static final Collection<String> EVENT_NAMES = Arrays.asList("change", "click");
 
   // todo generate
   @Override

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPage.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPage.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPage.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPage.java Thu Nov  3 11:28:25 2016
@@ -28,11 +28,14 @@ import org.slf4j.LoggerFactory;
 
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewRoot;
+import javax.faces.component.behavior.ClientBehaviorHolder;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
 
-public abstract class AbstractUIPage extends AbstractUIFormBase implements Visual {
+public abstract class AbstractUIPage extends AbstractUIFormBase implements Visual, ClientBehaviorHolder {
 
   private static final Logger LOG = LoggerFactory.getLogger(AbstractUIPage.class);
 
@@ -42,6 +45,22 @@ public abstract class AbstractUIPage ext
 
   private String formId;
 
+  // todo generate
+  private static final Collection<String> EVENT_NAMES = Arrays.asList("click", "resize", "load");
+
+  // todo generate
+  @Override
+  public String getDefaultEventName() {
+    return "click";
+  }
+
+  // todo generate
+  @Override
+  public Collection<String> getEventNames() {
+    return EVENT_NAMES;
+  }
+
+
   @Override
   public boolean getRendersChildren() {
     return true;

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIPanel.java Thu Nov  3 11:28:25 2016
@@ -19,5 +19,25 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
-public abstract class AbstractUIPanel extends AbstractUICollapsiblePanel {
+import javax.faces.component.behavior.ClientBehaviorHolder;
+import java.util.Arrays;
+import java.util.Collection;
+
+public abstract class AbstractUIPanel extends AbstractUICollapsiblePanel implements ClientBehaviorHolder {
+
+  // todo generate
+  private static final Collection<String> EVENT_NAMES = Arrays.asList("click", "mouseover", "mouseout");
+
+  // todo generate
+  @Override
+  public String getDefaultEventName() {
+    return "click";
+  }
+
+  // todo generate
+  @Override
+  public Collection<String> getEventNames() {
+    return EVENT_NAMES;
+  }
+
 }

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIProgress.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIProgress.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIProgress.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIProgress.java Thu Nov  3 11:28:25 2016
@@ -24,18 +24,37 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.faces.component.UIOutput;
+import javax.faces.component.behavior.ClientBehaviorHolder;
 import javax.faces.event.AbortProcessingException;
 import javax.faces.event.ComponentSystemEvent;
 import javax.faces.event.ComponentSystemEventListener;
 import javax.faces.event.ListenerFor;
 import javax.faces.event.PreRenderComponentEvent;
 import javax.swing.BoundedRangeModel;
+import java.util.Arrays;
+import java.util.Collection;
 
 @ListenerFor(systemEventClass = PreRenderComponentEvent.class)
-public abstract class AbstractUIProgress extends UIOutput implements Visual, ComponentSystemEventListener {
+public abstract class AbstractUIProgress extends UIOutput
+    implements Visual, ComponentSystemEventListener, ClientBehaviorHolder {
 
   private static final Logger LOG = LoggerFactory.getLogger(AbstractUIProgress.class);
 
+  // todo generate
+  private static final Collection<String> EVENT_NAMES = Arrays.asList("complete");
+
+  // todo generate
+  @Override
+  public String getDefaultEventName() {
+    return "complete";
+  }
+
+  // todo generate
+  @Override
+  public Collection<String> getEventNames() {
+    return EVENT_NAMES;
+  }
+
   private double rangeValue;
   private double rangeMax;
 

Copied: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIRow.java (from r1765603, myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnEvent.java)
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIRow.java?p2=myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIRow.java&p1=myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnEvent.java&r1=1765603&r2=1767871&rev=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnEvent.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIRow.java Thu Nov  3 11:28:25 2016
@@ -19,5 +19,28 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
-public class AbstractUIColumnEvent extends AbstractUIColumnBase {
+import javax.faces.component.behavior.ClientBehaviorHolder;
+import java.util.Arrays;
+import java.util.Collection;
+
+public class AbstractUIRow extends AbstractUIColumnBase implements ClientBehaviorHolder {
+
+  // todo generate
+  private static final Collection<String> EVENT_NAMES = Arrays.asList("click", "dblclick");
+
+  // todo generate
+  @Override
+  public String getDefaultEventName() {
+    return "click";
+  }
+
+
+
+
+  // todo generate
+  @Override
+  public Collection<String> getEventNames() {
+    return EVENT_NAMES;
+  }
+
 }

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java?rev=1767871&r1=1767870&r2=1767871&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java Thu Nov  3 11:28:25 2016
@@ -416,7 +416,7 @@ public abstract class AbstractUISheet ex
     final LayoutTokens tokens = new LayoutTokens();
     final List<AbstractUIColumnBase> columns = getAllColumns();
     for (final UIColumn column : columns) {
-      if (!(column instanceof AbstractUIColumnEvent)) {
+      if (!(column instanceof AbstractUIRow)) {
         tokens.addToken(RelativeLayoutToken.DEFAULT_INSTANCE);
       }
     }