You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by gc...@apache.org on 2013/05/17 22:33:02 UTC
svn commit: r1483979 - in /myfaces/trinidad/trunk/trinidad-api/src/main:
java/org/apache/myfaces/trinidad/change/
xrts/org/apache/myfaces/trinidad/resource/
Author: gcrawford
Date: Fri May 17 20:33:01 2013
New Revision: 1483979
URL: http://svn.apache.org/r1483979
Log:
TRINIDAD-2384 Need a notification mechanism for successful application of DocumentChange
Thanks to Prakash
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/BaseChangeManager.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManager.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManagerWrapper.java
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/SessionChangeManager.java
myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/BaseChangeManager.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/BaseChangeManager.java?rev=1483979&r1=1483978&r2=1483979&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/BaseChangeManager.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/BaseChangeManager.java Fri May 17 20:33:01 2013
@@ -22,10 +22,9 @@ import javax.faces.component.UIComponent
import javax.faces.context.FacesContext;
import org.apache.myfaces.trinidad.component.UIXIterator;
+import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
-import org.apache.myfaces.trinidad.util.ComponentUtils;
-
import org.w3c.dom.Document;
@@ -53,7 +52,7 @@ abstract class BaseChangeManager extends
// don't want to persist the changes
UIComponent parent = uiComponent.getParent();
UIComponent root = facesContext.getViewRoot();
- while (parent != null && parent != root)
+ while (parent != null && parent != root)
{
if (parent.getClass() == UIXIterator.class)
{
@@ -70,32 +69,15 @@ abstract class BaseChangeManager extends
// add the change to the component
addComponentChangeImpl(facesContext, uiComponent, change);
- if (supportsDocumentPersistence(facesContext))
- {
- DocumentChange docChange = null;
-
- if (change instanceof DocumentChange)
- {
- docChange = (DocumentChange)change;
- }
- else
- {
- // try to get equivalent DocumentChange from ComponentChange
- docChange = createDocumentChange(change);
- }
-
- if (docChange != null)
- {
- addDocumentChange(facesContext, uiComponent, docChange);
- }
- }
+ // add a corresponding DocumentChange if possible
+ _addEquivalentDocumentChange(facesContext, uiComponent, change);
}
-
+
/**
* A no-op implementation of adding a ComponentChange. Sub-classers should
* override and provide an implementation if they support component changes.
* @param facesContext The FacesContext for this request.
- * @param targetComponent The target component against which this change needs
+ * @param targetComponent The target component against which this change needs
* to be registered and applied later on.
* @param componentChange The ComponentChange to add
*/
@@ -123,7 +105,7 @@ abstract class BaseChangeManager extends
* in order to enable Document-based Persistence
*/
protected abstract Document getDocument(FacesContext context);
-
+
/**
* Returns true if we can support Document-based Persistence
* in this ChangeManager. Subclassers adding Document-based Persistence
@@ -137,6 +119,46 @@ abstract class BaseChangeManager extends
// correct, but potentially slow implementation
return getDocument(context) != null;
}
+
+ /*
+ * Create and add a DocumentChange corresponding to the supplied ComponentChange
+ */
+ private void _addEquivalentDocumentChange(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ ComponentChange compChange)
+ {
+ if (supportsDocumentPersistence(facesContext))
+ {
+ DocumentChange docChange = null;
+if (compChange instanceof DocumentChange)
+
+ {
+ docChange = (DocumentChange)compChange;
+ }
+ else
+ {
+ // try to get equivalent DocumentChange from ComponentChange
+ docChange = createDocumentChange(compChange);
+ }
+
+ if (docChange != null)
+ {
+ // We ("this" object) could be just a delegate of the top level change manager (i.e. the
+ // changemanager registered with the webapp). Automatically adding a document change (or
+ // deciding whether to add one) should be done by the top level changemanager
+ ChangeManager topChangeManager = RequestContext.getCurrentInstance().getChangeManager();
+
+ if ( ChangeOutcome.CHANGE_APPLIED ==
+ topChangeManager.addDocumentChangeWithOutcome(facesContext, uiComponent, docChange) )
+ {
+ // notify the registered change manager that we applied the document change
+ topChangeManager.documentChangeApplied(facesContext, uiComponent, compChange);
+ }
+ }
+ }
+ }
+
private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
BaseChangeManager.class);
}
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManager.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManager.java?rev=1483979&r1=1483978&r2=1483979&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManager.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManager.java Fri May 17 20:33:01 2013
@@ -36,6 +36,8 @@ import org.apache.myfaces.trinidad.loggi
* take care of their persistence.
* @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/change/ChangeManager.java#0 $) $Date: 10-nov-2005.19:09:58 $
*/
+// WHENEVER A NEW METHOD IS ADDED TO THIS CLASS, REMEMBER TO ADD AN IMPLEMENTATION TO
+// org.apache.myfaces.trinidad.change.ChangeManagerWrapper
public abstract class ChangeManager
{
public static void registerDocumentFactory(
@@ -108,7 +110,7 @@ public abstract class ChangeManager
else
{
// log warning because class isn't correct type
- _LOG.warning("CONVERSION_CLASS_TYPE", new Object[] {converterClass, DocumentChangeFactory.class}); // NOTRANS
+ _LOG.warning("CONVERSION_CLASS_TYPE", new Object[] {converterClass, DocumentChangeFactory.class});
}
}
catch (Throwable e)
@@ -137,18 +139,31 @@ public abstract class ChangeManager
}
/**
- * Add a ComponentChange to this current request for a specified component.
- * When called we will disallow changes if the component or its any ancestor
- * is a stamped component by UIXIterator.
- *
- * @throws IllegalArgumentException if any of the supplied parameters were to
- * be null.
+ * Adds a ComponentChange to the current request for a specified component. Component changes
+ * cannot be added for stamped children of an UIXIterator.
+ *
+ * A DocumentChange will be automatically created and applied on the ChangeManager registered
+ * for this application if the following conditions are met:
+ * 1. The ChangeManager registered for the application supports document change persistence
+ * 2. DocumentChange corresponding to the supplied ComponentChange can be created with the help
+ * of any registered DocumentChangeFactory
+ * When such a DocumentChange is added, the ChangeManager registered for the application is
+ * notified by means of calling its documentChangeApplied() method. This is to give the
+ * registered ChangeManager an opportunity to take any necessary action. For example, Session
+ * based ChangeManager implementations may choose to remove the ComponentChange, if any added
+ * earlier. Custom ChangeManager implementations should notify likewise if it automatically
+ * creates and adds a DocumentChange.
+ *
+ * @throws IllegalArgumentException if any of the supplied parameters were to be null.
+ *
+ * @see DocumentChangeFactory
+ * @see #documentChangeApplied(FacesContext, UIComponent, ComponentChange
*/
public abstract void addComponentChange(
FacesContext facesContext,
UIComponent uiComponent,
ComponentChange change);
-
+
/**
* Replace an AttributeComponentChange if it's present.
*
@@ -157,7 +172,8 @@ public abstract class ChangeManager
* @param attributeComponentChange
* @return the old change instance
*/
- public AttributeComponentChange replaceAttributeChangeIfPresent(FacesContext facesContext,
+ public AttributeComponentChange replaceAttributeChangeIfPresent(
+ FacesContext facesContext,
UIComponent uiComponent,
AttributeComponentChange attributeComponentChange)
{
@@ -167,23 +183,78 @@ public abstract class ChangeManager
/**
* Add a DocumentChange to this current request for a specified component.
- * When called we will allow changes even if the component or its any ancestor
+ * When called we will allow changes even if the component or its any ancestor
* is a stamped component by UIXIterator.
- *
+ *
* @throws IllegalArgumentException if any of the supplied parameters were to
- * be null.
+ * be null.
+ *
+ * @deprecated use
+ * {@link ChangeManager#addDocumentChangeWithOutcome(javax.faces.context.FacesContext,javax.faces.component.UIComponent,org.apache.myfaces.trinidad.change.DocumentChange)}
+ * instead
*/
+ @Deprecated
public void addDocumentChange(
- FacesContext facesContext,
- UIComponent uiComponent,
- DocumentChange change)
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ DocumentChange change)
{
if (facesContext == null || uiComponent == null || change == null)
throw new IllegalArgumentException(_LOG.getMessage(
"CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL"));
}
+
+ /**
+ * Add a DocumentChange for a specified component, and return the outcome of adding the change.
+ *
+ * @param facesContext The FacesContext instance for the current request
+ * @param uiComponent The UIComponent instance for which the DocumentChange is to be added
+ * @param change The DocumentChange to be added
+ *
+ * @return The outcome of adding the document change
+ *
+ * @throws IllegalArgumentException if any of the supplied parameters were to
+ * be null.
+ *
+ * @see ChangeOutcome
+ */
+ public ChangeOutcome addDocumentChangeWithOutcome(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ DocumentChange change)
+ {
+ addDocumentChange(facesContext, uiComponent, change);
+
+ return ChangeOutcome.UNKNOWN;
+ }
/**
+ * This method is called on the registered ChangeManager if a ChangeManager in its
+ * addComponentChange() implementation automatically creates an equivalent DocumentChange and
+ * applies the change. The registered ChangeManager may choose to take some action based on
+ * the outcome of applying the document change. For example, session based ChangeManager
+ * implementations may choose to remove any earlier added ComponentChange if an equivalent
+ * document change is now successfully applied
+ *
+ * @param component The target UIComponent instance for which the DocumentChange was
+ * applied
+ * @param componentChange The ComponentChange for which an equivalent DocumentChange was applied
+ *
+ * @return The outcome of handling this notification
+ *
+ * @throws IllegalArgumentException if the supplied ComponentChange is null. *
+ */
+ public NotificationOutcome documentChangeApplied(
+ FacesContext facesContext,
+ UIComponent component,
+ ComponentChange componentChange)
+ {
+ if (componentChange == null)
+ throw new IllegalArgumentException("The supplied ComponentChange object is null");
+ return NotificationOutcome.NOT_HANDLED;
+ }
+
+ /**
* Applies all the ComponentChanges added so far for the current view.
* Developers should not need to call this method. Internal implementation
* will call it as the component tree is built and is ready to take changes.
@@ -208,12 +279,11 @@ public abstract class ChangeManager
*/
public void applyComponentChangesForSubtree(
FacesContext facesContext,
- NamingContainer root
- )
+ NamingContainer root)
{
throw new UnsupportedOperationException("Subclassers must implement");
}
-
+
/**
* Apply non-cross-component changes to a component in its original location. This is typically
* only called by tags that need to ensure that a newly created component instance is
@@ -226,6 +296,38 @@ public abstract class ChangeManager
throw new UnsupportedOperationException("Subclassers must implement");
}
+ /**
+ * Indicates the outcome of the attempt to apply a Change. Possible outcomes are:
+ * 1. UNKNOWN - We do not know if the change was applied or not
+ * 2. CHANGE_APPLIED - Change was successfully applied
+ * 3. CHANGE_NOT_APPLIED - There was a failure when applying the Change
+ *
+ * @see #addDocumentChangeWithOutcome(FacesContext,UIComponent,DocumentChange)
+ */
+ public static enum ChangeOutcome
+ {
+ UNKNOWN,
+ CHANGE_APPLIED,
+ CHANGE_NOT_APPLIED;
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * Indicates whether the notification was handled:
+ * 1. HANDLED - Notification was handled
+ * 2. NOT_HANDLED - Notification was not handled
+ *
+ * @see #documentChangeApplied(FacesContext, UIComponent, ComponentChange)
+ */
+ public static enum NotificationOutcome
+ {
+ HANDLED,
+ NOT_HANDLED;
+
+ private static final long serialVersionUID = 1L;
+ }
+
private static class AttributeConverter extends DocumentChangeFactory
{
@Override
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManagerWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManagerWrapper.java?rev=1483979&r1=1483978&r2=1483979&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManagerWrapper.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/ChangeManagerWrapper.java Fri May 17 20:33:01 2013
@@ -1,94 +1,135 @@
-/*
- * 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.trinidad.change;
-
-import javax.faces.component.NamingContainer;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-
-import org.apache.myfaces.trinidad.change.ChangeManager;
-import org.apache.myfaces.trinidad.change.ComponentChange;
-import org.apache.myfaces.trinidad.change.DocumentChange;
-
-/**
- * Base class for ChangeManager implementations that wrap other ChangeManagers.
- */
-abstract public class ChangeManagerWrapper extends ChangeManager
-{
- /**
- * Delegates the addComponentChange() implementation to the wrapped
- * ChangeManager.
- */
- @Override
- public void addComponentChange(
- FacesContext context,
- UIComponent component,
- ComponentChange change)
- {
- getWrappedChangeManager().addComponentChange(context, component, change);
- }
-
- /**
- * Delegates the addDocumentChange() implementation to the wrapped
- * ChangeManager.
- */
- @Override
- public void addDocumentChange(
- FacesContext context,
- UIComponent component,
- DocumentChange change)
- {
- getWrappedChangeManager().addDocumentChange(context, component, change);
- }
-
- /**
- * Delegates the applyComponentChangesForCurrentView() implementation to
- * the wrapped ChangeManager.
- */
- @Override
- public void applyComponentChangesForCurrentView(FacesContext context)
- {
- getWrappedChangeManager().applyComponentChangesForCurrentView(context);
- }
-
- /**
- * Delegates the applyComponentChangesForSubtree() implementation to the
- * wrapped ChangeManager.
- */
- @Override
- public void applyComponentChangesForSubtree(FacesContext context, NamingContainer root)
- {
- getWrappedChangeManager().applyComponentChangesForSubtree(context, root);
- }
-
- /**
- * Delegates the applySimpleComponentChanges() implementation to the wrapped
- * ChangeManager.
- */
- @Override
- public void applySimpleComponentChanges(FacesContext context, UIComponent component)
- {
- getWrappedChangeManager().applySimpleComponentChanges(context, component);
- }
-
- /**
- * Returns the wrapped ChangeManager.
- */
- abstract protected ChangeManager getWrappedChangeManager();
-}
+/*
+ * 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.trinidad.change;
+
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+
+/**
+ * Base class for ChangeManager implementations that wrap other ChangeManagers.
+ */
+abstract public class ChangeManagerWrapper extends ChangeManager
+{
+ /**
+ * Delegates the addComponentChange() implementation to the wrapped
+ * ChangeManager.
+ */
+ @Override
+ public void addComponentChange(
+ FacesContext context,
+ UIComponent component,
+ ComponentChange change)
+ {
+ getWrappedChangeManager().addComponentChange(context, component, change);
+ }
+
+ /**
+ * Delegates the addDocumentChange() implementation to the wrapped ChangeManager.
+ *
+ * @see #addDocumentChangeWithOutcome(FacesContext, UIComponent, DocumnentChange)
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public void addDocumentChange(
+ FacesContext context,
+ UIComponent component,
+ DocumentChange change)
+ {
+ getWrappedChangeManager().addDocumentChange(context, component, change);
+ }
+
+ /**
+ * Delegates the applyComponentChangesForCurrentView() implementation to
+ * the wrapped ChangeManager.
+ */
+ @Override
+ public void applyComponentChangesForCurrentView(FacesContext context)
+ {
+ getWrappedChangeManager().applyComponentChangesForCurrentView(context);
+ }
+
+ /**
+ * Delegates the applyComponentChangesForSubtree() implementation to the
+ * wrapped ChangeManager.
+ */
+ @Override
+ public void applyComponentChangesForSubtree(FacesContext context, NamingContainer root)
+ {
+ getWrappedChangeManager().applyComponentChangesForSubtree(context, root);
+ }
+
+ /**
+ * Delegates the applySimpleComponentChanges() implementation to the wrapped
+ * ChangeManager.
+ */
+ @Override
+ public void applySimpleComponentChanges(FacesContext context, UIComponent component)
+ {
+ getWrappedChangeManager().applySimpleComponentChanges(context, component);
+ }
+
+ /**
+ * Delegates the documentChangeApplied() implementation to the wrapped ChangeManager.
+ */
+ @Override
+ public NotificationOutcome documentChangeApplied(
+ FacesContext facesContext,
+ UIComponent component,
+ ComponentChange componentChange)
+ {
+ return getWrappedChangeManager().documentChangeApplied(facesContext,
+ component,
+ componentChange);
+ }
+
+ /**
+ * Delegates the addDocumentChangeWithOutcome() implementation to the wrapped ChangeManager.
+ */
+ @Override
+ public ChangeOutcome addDocumentChangeWithOutcome(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ DocumentChange change)
+ {
+ return getWrappedChangeManager().addDocumentChangeWithOutcome(facesContext,
+ uiComponent,
+ change);
+ }
+
+ /**
+ * Delegates the replaceAttributeChangeIfPresent() implementation to the wrapped ChangeManager.
+ */
+ @Override
+ public AttributeComponentChange replaceAttributeChangeIfPresent(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ AttributeComponentChange attributeComponentChange)
+ {
+ return getWrappedChangeManager().replaceAttributeChangeIfPresent(facesContext,
+ uiComponent,
+ attributeComponentChange);
+ }
+
+ /**
+ * Returns the wrapped ChangeManager.
+ */
+ abstract protected ChangeManager getWrappedChangeManager();
+}
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/SessionChangeManager.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/SessionChangeManager.java?rev=1483979&r1=1483978&r2=1483979&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/SessionChangeManager.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/SessionChangeManager.java Fri May 17 20:33:01 2013
@@ -42,18 +42,15 @@ import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
-import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.util.CollectionUtils;
import org.apache.myfaces.trinidad.util.ComponentUtils;
-import org.apache.myfaces.trinidad.webapp.UIXComponentELTag;
-
import org.w3c.dom.Document;
/**
- * A ChangeManager implementation that manages persisting the added Changes at the session.
+ * A ChangeManager implementation that manages persisting the added Changes at the session.
* This means the lifetime of Changes added such is within the session scope. If any of the changes
* are managed as state changes and restored by JSF state saving mechanism, the SessionChangeManager
* will not re-apply such changes. For example: AttributeComponentChanges are not applied during
@@ -120,6 +117,72 @@ public class SessionChangeManager extend
}
/**
+ * @inheritDoc
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public void addDocumentChange(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ DocumentChange change)
+ {
+ addDocumentChangeWithOutcome(facesContext, uiComponent, change);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public ChangeOutcome addDocumentChangeWithOutcome(
+ FacesContext facesContext,
+ UIComponent uiComponent,
+ DocumentChange change)
+ {
+ if (facesContext == null || uiComponent == null || change == null)
+ throw new IllegalArgumentException(_LOG.getMessage(
+ "CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL"));
+
+ return ChangeOutcome.CHANGE_NOT_APPLIED;
+ }
+
+ /**
+ * In this implementation, if a simple attribute document change was applied, we will remove
+ * previously added component change on the same component and attribute, if any.
+ */
+ @Override
+ public NotificationOutcome documentChangeApplied(
+ FacesContext facesContext,
+ UIComponent component,
+ ComponentChange componentChange)
+ {
+ NotificationOutcome outcome = super.documentChangeApplied(facesContext,
+ component,
+ componentChange);
+
+ if (componentChange instanceof AttributeComponentChange)
+ {
+ AttributeComponentChange attributeChange = (AttributeComponentChange)componentChange;
+ // given that document change was applied, any previously added component change is redundant,
+ // remove it
+ ComponentChange removedChange = _removeSimpleComponentChange(facesContext,
+ component,
+ attributeChange);
+
+ if (removedChange != null)
+ {
+ if (_LOG.isFine())
+ {
+ _LOG.fine("REMOVED_DOC_CHANGE_BECAUSE_COMP_CHANGE_ADDED", new Object[] {attributeChange.getAttributeName(), component});
+ }
+
+ outcome = NotificationOutcome.HANDLED;
+ }
+ }
+
+ return outcome;
+ }
+
+ /**
* Adds a ComponentChange and registers against the supplied component.
* Changes added thus live at Session scope.
* Use applyComponentChangesForCurrentView() to apply these changes.
@@ -139,6 +202,7 @@ public class SessionChangeManager extend
{
_replaceAttributeChange(context,
targetComponent,
+ ((AttributeComponentChange)componentChange).getAttributeName(),
(AttributeComponentChange)componentChange,
false); // replace no matter what
}
@@ -155,7 +219,10 @@ public class SessionChangeManager extend
String logicalScopedIdForTargetComponent =
ComponentUtils.getLogicalScopedIdForComponent(targetComponent, context.getViewRoot());
- _insertComponentChange(changesForView, scopedIdForTargetComponent, logicalScopedIdForTargetComponent, componentChange);
+ _insertComponentChange(changesForView,
+ scopedIdForTargetComponent,
+ logicalScopedIdForTargetComponent,
+ componentChange);
// dirty the key in the session for failover
context.getExternalContext().getSessionMap().put(sessionKey, changesForView);
@@ -171,7 +238,11 @@ public class SessionChangeManager extend
UIComponent component,
AttributeComponentChange attributeComponentChange)
{
- return _replaceAttributeChange(context, component, attributeComponentChange, true);
+ return _replaceAttributeChange(context,
+ component,
+ attributeComponentChange.getAttributeName(),
+ attributeComponentChange,
+ true);
}
/**
@@ -184,19 +255,50 @@ public class SessionChangeManager extend
}
/**
- *
+ * Removes (if any) the previously added simple component change for the supplied component and
+ * attribute
+ *
+ * @return The removed ComponentChange instance, or null if the ComponentChange was not removed
+ */
+ private ComponentChange _removeSimpleComponentChange(
+ FacesContext facesContext,
+ UIComponent component,
+ AttributeComponentChange componentChange)
+ {
+ String sessionKey = _getSessionKey(facesContext);
+ ChangesForView changesForView = _getChangesForView(facesContext, sessionKey, true);
+ String logicalScopedId =
+ ComponentUtils.getLogicalScopedIdForComponent(component, facesContext.getViewRoot());
+
+ // first remove from the simple component changes structure that we maintained for convenience
+ changesForView.removeAttributeChange(logicalScopedId, componentChange);
+
+ // next, remove (replace with null) any attribute change for this attribute from the global
+ // changes list, handling the case where the component could have been moved after the
+ // attribute change was added
+ return _replaceAttributeChange(facesContext,
+ component,
+ componentChange.getAttributeName(),
+ null,
+ true);
+ }
+
+ /**
* @param context
* @param component
- * @param attributeComponentChange
+ * @param attributeName The name of the attribute for which the attribute change is to be replaced
+ * @param attributeComponentChange The attributeChange that should now replace, If null, we just remove the old one
+ * and return
* @param onlyIfPresent If true, we only insert a new changed if we removed an old one
* @return the removed AttributeComponentChange, if any
*/
private AttributeComponentChange _replaceAttributeChange(
FacesContext context,
UIComponent component,
+ String attributeName,
AttributeComponentChange attributeComponentChange,
boolean onlyIfPresent)
- {
+ {
// get the absolute scopedId for the target component so that we have a unique identifier
// to compare
String scopedIdForTargetComponent = ComponentUtils.getScopedIdForComponent(
@@ -208,18 +310,29 @@ public class SessionChangeManager extend
String sessionKey = _getSessionKey(context);
ChangesForView changesForView = _getChangesForView(context, sessionKey, true);
+ // remove the attribute change first if it existed
AttributeComponentChange replaced = _extractAttributeChange(changesForView,
scopedIdForTargetComponent,
- attributeComponentChange);
+ attributeName);
- // if found, we insert the new change instance
- if (!onlyIfPresent || (replaced != null))
+ // if found, we insert the change instance we are asked to replace with
+ if ( attributeComponentChange != null && (!onlyIfPresent || (replaced != null)) )
{
+ // a sanity check - the change better be for the same attribute
+ if ( !(attributeName.equals(attributeComponentChange.getAttributeName())) )
+ {
+ throw new IllegalArgumentException("The supplied attribute name does not match the " +
+ "attribute name in the supplied attribute change");
+ }
+
String logicalScopedIdForTargetComponent = ComponentUtils.getLogicalScopedIdForComponent(
component,
context.getViewRoot());
- _insertComponentChange(changesForView, scopedIdForTargetComponent, logicalScopedIdForTargetComponent, attributeComponentChange);
+ _insertComponentChange(changesForView,
+ scopedIdForTargetComponent,
+ logicalScopedIdForTargetComponent,
+ attributeComponentChange);
// dirty the key in the session for failover
context.getExternalContext().getSessionMap().put(sessionKey, changesForView);
@@ -233,19 +346,20 @@ public class SessionChangeManager extend
* - if not found, return null
* - if found, remove and return the old change instance
*
+ * Note that this function will handle removing a component's attribute change even if the
+ * component was moved between naming containers after the attribute change was added
+ *
* @param changesForView
* @param scopedIdForTargetComponent
- * @param attributeChange
+ * @param attributeName The name of attribute for which the attribute change is to be extracted
* @return the old change instance, null if not found
*/
private AttributeComponentChange _extractAttributeChange(
- ChangesForView changesForView,
- String scopedIdForTargetComponent,
- AttributeComponentChange attributeChange)
+ ChangesForView changesForView,
+ String scopedIdForTargetComponent,
+ String attributeName)
{
AttributeComponentChange extracted = null;
-
- String attributeName = attributeChange.getAttributeName();
// would really rather use a Deque here and iterate backwards, which would also make
// handling the rename changes easier
@@ -446,7 +560,7 @@ public class SessionChangeManager extend
/**
* Is the state restored by JSF state manager in this request. This is usually true if this is a
* postback request. Additionally check if the document tag created a document component, because
- * if this is the case, we are sure that there was no state restoration.
+ * if this is the case, we are sure that there was no state restoration.
*/
private boolean _isStateRestored(FacesContext facesContext)
{
@@ -568,7 +682,7 @@ public class SessionChangeManager extend
return builder.append(_COMPONENT_CHANGES_MAP_FOR_SESSION_KEY).append(viewId).toString();
}
-
+
/**
* Tracks the component changes for a particular view as well as all the movement
* changes so that component aliasing can be tracked
@@ -635,7 +749,7 @@ public class SessionChangeManager extend
// make sure that we don't add changes while getAttrChanges() is rebuilding the
// per-component changes
_componentChangesForView.add(qualifiedChange);
-
+
ComponentChange componentChange = qualifiedChange.getComponentChange();
if (componentChange instanceof AttributeComponentChange)
@@ -659,6 +773,24 @@ public class SessionChangeManager extend
}
}
}
+
+ /**
+ * Removes any previously stored attribute change for this component and attribute. Any moves
+ * later to an earlier addition of attribute change is taken care of, by means of removing such
+ * attribute change.
+ * @return The attribute change that was removed
+ */
+ protected AttributeComponentChange removeAttributeChange(
+ String logicalScopedId,
+ AttributeComponentChange attributeChange)
+ {
+ // remove this change from the attribute changes map that gets used for applying simple
+ // component changes
+ return _removeAttributeChange(_attrChanges,
+ _renameMap,
+ logicalScopedId,
+ attributeChange);
+ }
/**
* Returns the Iterator of rename changes that affect the current scoped id in ComponentChange order
@@ -720,54 +852,98 @@ public class SessionChangeManager extend
// all phases including tag execution
String scopedId = ComponentUtils.getLogicalScopedIdForComponent(component, context.getViewRoot());
- ConcurrentMap<String, ComponentChange> componentChanges = _attrChanges.get(scopedId);
+ ConcurrentMap<String, AttributeComponentChange> attributeCmponentChanges = _attrChanges.get(scopedId);
- if (componentChanges != null)
+ if (attributeCmponentChanges != null)
{
- for (ComponentChange change : componentChanges.values())
+ for (ComponentChange change : attributeCmponentChanges.values())
{
change.changeComponent(component);
}
}
}
-
+
private void _updateAttributeChange(
- ConcurrentMap<String, ConcurrentMap<String, ComponentChange>> attrChanges,
- ConcurrentMap<String, String> renameMap,
- QualifiedComponentChange qAttrChange)
+ ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
+ ConcurrentMap<String, String> renameMap,
+ QualifiedComponentChange qAttrChange)
+ {
+ // get all the attribute changes for this component after considering possible moves.
+ // We want to update, so create if necessary
+ ConcurrentMap<String, AttributeComponentChange> changesForComponent =
+ _getAttributeChangesAfterHandlingMove(attrChanges,
+ renameMap,
+ qAttrChange.getTargetComponentLogicalScopedId(),
+ true);
+
+ AttributeComponentChange attrChange = (AttributeComponentChange)
+ qAttrChange.getComponentChange();
+
+ // update the current AttributeComponentChange for this attribute
+ String attrName = attrChange.getAttributeName();
+
+ changesForComponent.put(attrName, attrChange);
+ }
+
+ private AttributeComponentChange _removeAttributeChange(
+ ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
+ ConcurrentMap<String, String> renameMap,
+ String logicalScopedId,
+ AttributeComponentChange componentChange)
{
- // update the current attribute values for the scoped id
- String currScopedId = qAttrChange.getTargetComponentLogicalScopedId();
+ // get all the attribute changes for this component after considering possible moves
+ ConcurrentMap<String, AttributeComponentChange> changesForComponent =
+ _getAttributeChangesAfterHandlingMove(attrChanges, renameMap, logicalScopedId, false);
- // apply any move rename
- String originalScopedId = renameMap.get(currScopedId);
+ if (changesForComponent != null)
+ {
+ return changesForComponent.remove(componentChange.getAttributeName());
+ }
- // we don't add rename mapping until a move, so if there is no entry, the origina
- // value is good
+ return null;
+ }
+
+ /**
+ * Gets the map of all the attribute changes for a component with the supplied logical scoped id.
+ *
+ * @param attrChanges The map of attribute change collection per component keyed by the id
+ * @param renameMap The id renaming map for moved components
+ * @param logicalScopedId The logical scoped id of the component for which attribute changes are
+ * needed
+ * @param createIfNecessary Create the attribute changes map if there are no attribute changes
+ * for the component with supplied logical scoped id.
+ * @return The map of attribute changes keyed by the attribute name
+ */
+ private ConcurrentMap<String, AttributeComponentChange> _getAttributeChangesAfterHandlingMove(
+ ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> attrChanges,
+ ConcurrentMap<String, String> renameMap,
+ String logicalScopedId,
+ boolean createIfNecessary)
+ {
+ // handle renames due to possible moves and get the original id
+ String originalScopedId = renameMap.get(logicalScopedId);
+
+ // we don't add rename mapping until a move, so if there is no entry, the component did not
+ // move, the original value is good
if (originalScopedId == null)
- originalScopedId = currScopedId;
+ {
+ originalScopedId = logicalScopedId;
+ }
- // get the map for this component, creating one if necessary
- ConcurrentMap<String, ComponentChange> changesForComponent =
+ // get the map of attribute changes for this component, creating one if necessary
+ ConcurrentMap<String, AttributeComponentChange> changesForComponent =
attrChanges.get(originalScopedId);
// if we haven't registered a Map yet, create one and register it
- if (changesForComponent == null)
+ if (changesForComponent == null && createIfNecessary)
{
// =-= bts There probably aren't that many different changes per component. Maybe
// we need something smaller and more efficient here
- changesForComponent = new ConcurrentHashMap<String, ComponentChange>();
+ changesForComponent = new ConcurrentHashMap<String, AttributeComponentChange>();
attrChanges.put(originalScopedId, changesForComponent);
}
- AttributeComponentChange attrChange = (AttributeComponentChange)
- qAttrChange.getComponentChange();
-
- // update the current AttributeComponentChange for this attribute
- String attrName = attrChange.getAttributeName();
-
- changesForComponent.put(attrName, attrChange);
-
+ return changesForComponent;
}
/**
@@ -798,7 +974,7 @@ public class SessionChangeManager extend
renameMap.put(destinationScopedId, originalScodeId);
}
}
-
+
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
@@ -839,15 +1015,14 @@ public class SessionChangeManager extend
private static final long serialVersionUID = 1L;
}
-
-
+
private final Queue<QualifiedComponentChange> _componentChangesForView;
private final List<MoveChildComponentChange> _renameChanges;
// map of original scopedIds to Map of attribute names and their new values. This allows
// us to apply all of attribute changes efficiently
- private final ConcurrentMap<String, ConcurrentMap<String, ComponentChange>> _attrChanges =
- new ConcurrentHashMap<String, ConcurrentMap<String, ComponentChange>>();
+ private final ConcurrentMap<String, ConcurrentMap<String, AttributeComponentChange>> _attrChanges =
+ new ConcurrentHashMap<String, ConcurrentMap<String, AttributeComponentChange>>();
// map of current scoped ids to original scoped ids. This enables us to correctly update
// the attributes for the original scoped ids even after the component has moved
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts?rev=1483979&r1=1483978&r2=1483979&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts Fri May 17 20:33:01 2013
@@ -201,6 +201,9 @@
<!-- CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL -->
<resource key="CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL">Cannot add a Change with either of FacesContext, UIComponent or Change being null.</resource>
+ <!-- REMOVED_DOC_CHANGE_BECAUSE_COMP_CHANGE_ADDED -->
+ <resource key="REMOVED_DOC_CHANGE_BECAUSE_COMP_CHANGE_ADDED">AttributeComponentChange for the attribute {1} on the component {2} was removed because an equivalent DocumentChange was added.</resource>
+
<!-- CANNOT_CONSTRUCT_CHANGECOMPONENTPROXY_WITH_NULL_UICOMPONENT -->
<resource key="CANNOT_CONSTRUCT_CHANGECOMPONENTPROXY_WITH_NULL_UICOMPONENT">Cannot construct an ChangeComponentProxy with null UIComponent.</resource>