Index: faces/context/BridgeFacesContext.java =================================================================== --- faces/context/BridgeFacesContext.java (revision 214) +++ faces/context/BridgeFacesContext.java (working copy) @@ -467,19 +467,24 @@ if (document == null) return; Map parameters = externalContext.getRequestParameterValuesMap(); - NodeList formElements = document.getElementsByTagName("form"); - int formElementsLength = formElements.getLength(); - for (int i = 0; i < formElementsLength; i++) { - Element formElement = (Element) formElements.item(i); - String id = formElement.getAttribute("id"); - //String formClientId = ((String[]) parameters.get(id))[0]; - //if (formClientId != null && formClientId.equals(id)) { - if (parameters.containsKey(id)) { - applyBrowserFormChanges(parameters, document, formElement); - break; // This assumes only one form is submitted + view.aquireDOMLock(); + try { + NodeList formElements = document.getElementsByTagName("form"); + int formElementsLength = formElements.getLength(); + for (int i = 0; i < formElementsLength; i++) { + Element formElement = (Element) formElements.item(i); + String id = formElement.getAttribute("id"); + //String formClientId = ((String[]) parameters.get(id))[0]; + //if (formClientId != null && formClientId.equals(id)) { + if (parameters.containsKey(id)) { + applyBrowserFormChanges(parameters, document, formElement); + break; // This assumes only one form is submitted + } } + documentStore.cache(document); + } finally { + view.releaseDOMLock(); } - documentStore.cache(document); } protected void applyBrowserFormChanges(Map parameters, Document document, Element form) { Index: faces/context/PushModeSerializer.java =================================================================== --- faces/context/PushModeSerializer.java (revision 214) +++ faces/context/PushModeSerializer.java (working copy) @@ -66,69 +66,74 @@ } public void serialize(final Document document) throws IOException { - Node[] changed = DOMUtils.domDiff(store.load(), document); - HashMap depthMaps = new HashMap(); - for (int i = 0; i < changed.length; i++) { - Element changeRoot = - DOMUtils.ascendToNodeWithID(changed[i]); - changed[i] = changeRoot; - Integer depth = new Integer(getDepth(changeRoot)); - HashSet peers = (HashSet) depthMaps.get(depth); - if (null == peers) { - peers = new HashSet(); - depthMaps.put(depth, peers); + view.aquireDOMLock(); + try { + Node[] changed = DOMUtils.domDiff(store.load(), document); + HashMap depthMaps = new HashMap(); + for (int i = 0; i < changed.length; i++) { + Element changeRoot = + DOMUtils.ascendToNodeWithID(changed[i]); + changed[i] = changeRoot; + Integer depth = new Integer(getDepth(changeRoot)); + HashSet peers = (HashSet) depthMaps.get(depth); + if (null == peers) { + peers = new HashSet(); + depthMaps.put(depth, peers); + } + //place the node in a collection of all nodes + //at its same depth in the DOM + peers.add(changeRoot); } - //place the node in a collection of all nodes - //at its same depth in the DOM - peers.add(changeRoot); - } - Iterator allDepths = depthMaps.keySet().iterator(); - while (allDepths.hasNext()) { - Integer baseDepth = (Integer) allDepths.next(); - Iterator checkDepths = depthMaps.keySet().iterator(); - while (checkDepths.hasNext()) { - Integer checkDepth = (Integer) checkDepths.next(); - if (baseDepth.intValue() < checkDepth.intValue()) { - pruneAncestors(baseDepth, (HashSet) depthMaps.get(baseDepth), - checkDepth, (HashSet) depthMaps.get(checkDepth)); + Iterator allDepths = depthMaps.keySet().iterator(); + while (allDepths.hasNext()) { + Integer baseDepth = (Integer) allDepths.next(); + Iterator checkDepths = depthMaps.keySet().iterator(); + while (checkDepths.hasNext()) { + Integer checkDepth = (Integer) checkDepths.next(); + if (baseDepth.intValue() < checkDepth.intValue()) { + pruneAncestors(baseDepth, (HashSet) depthMaps.get(baseDepth), + checkDepth, (HashSet) depthMaps.get(checkDepth)); + } } } - } - //Merge all remaining elements at different depths - //Collection is a Set so duplicates will be discarded - HashSet topElements = new HashSet(); - Iterator allDepthMaps = depthMaps.values().iterator(); - while (allDepthMaps.hasNext()) { - topElements.addAll((HashSet) allDepthMaps.next()); - } + //Merge all remaining elements at different depths + //Collection is a Set so duplicates will be discarded + HashSet topElements = new HashSet(); + Iterator allDepthMaps = depthMaps.values().iterator(); + while (allDepthMaps.hasNext()) { + topElements.addAll((HashSet) allDepthMaps.next()); + } - if (!topElements.isEmpty()) { - boolean reload = false; - int j = 0; - Element[] elements = new Element[topElements.size()]; - HashSet dupCheck = new HashSet(); - //copy the succsessful changed elements and check for change - //to head or body - for (int i = 0; i < changed.length; i++) { - Element element = (Element) changed[i]; - String tag = element.getTagName(); - //send reload command if 'html', 'body', or 'head' elements need to be updated (see: ICE-3063) - reload = reload || "html".equalsIgnoreCase(tag) || "head".equalsIgnoreCase(tag); - if (topElements.contains(element)) { - if (!dupCheck.contains(element)) { - dupCheck.add(element); - elements[j++] = element; + if (!topElements.isEmpty()) { + boolean reload = false; + int j = 0; + Element[] elements = new Element[topElements.size()]; + HashSet dupCheck = new HashSet(); + //copy the succsessful changed elements and check for change + //to head or body + for (int i = 0; i < changed.length; i++) { + Element element = (Element) changed[i]; + String tag = element.getTagName(); + //send reload command if 'html', 'body', or 'head' elements need to be updated (see: ICE-3063) + reload = reload || "html".equalsIgnoreCase(tag) || "head".equalsIgnoreCase(tag); + if (topElements.contains(element)) { + if (!dupCheck.contains(element)) { + dupCheck.add(element); + elements[j++] = element; + } } } + if (reload) { + //reload document instead of applying an update for the entire page (see: ICE-2189) + view.preparePage(new PreparedPage(document)); + view.put(new Reload(viewNumber)); + } else { + view.put(new UpdateElements(view, coalesce, elements)); + } } - if (reload) { - //reload document instead of applying an update for the entire page (see: ICE-2189) - view.preparePage(new PreparedPage(document)); - view.put(new Reload(viewNumber)); - } else { - view.put(new UpdateElements(coalesce, elements)); - } + } finally { + view.releaseDOMLock(); } } Index: faces/context/View.java =================================================================== --- faces/context/View.java (revision 214) +++ faces/context/View.java (working copy) @@ -53,6 +53,7 @@ import com.icesoft.faces.webapp.http.servlet.SessionDispatcher; import com.icesoft.faces.webapp.parser.ImplementationUtil; import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState; +import com.icesoft.util.DOMLockController; import com.icesoft.util.SeamUtilities; import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock; @@ -67,7 +68,7 @@ import java.util.Iterator; import java.util.Map; -public class View implements CommandQueue { +public class View implements CommandQueue, DOMLockController { public static final String ICEFACES_STATE_MAPS = "icefaces.state.maps"; private static final Log Log = LogFactory.getLog(View.class); @@ -133,6 +134,7 @@ private Page page = lifecycleExecutedPage; private final ReentrantLock queueLock = new ReentrantLock(); private final ReentrantLock lifecycleLock = new ReentrantLock(); + private final ReentrantLock domLock = new ReentrantLock(); private BridgeFacesContext facesContext; private PersistentFacesState persistentFacesState; private Command currentCommand = NOOP; @@ -364,6 +366,14 @@ onReleaseListeners.add(runnable); } + public void aquireDOMLock() { + domLock.lock(); + } + + public void releaseDOMLock() { + domLock.unlock(); + } + private interface Page { void serve(Request request) throws Exception; } Index: faces/webapp/command/UpdateElements.java =================================================================== --- faces/webapp/command/UpdateElements.java (revision 214) +++ faces/webapp/command/UpdateElements.java (working copy) @@ -33,6 +33,7 @@ package com.icesoft.faces.webapp.command; import com.icesoft.faces.util.DOMUtils; +import com.icesoft.util.DOMLockController; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -46,10 +47,12 @@ public class UpdateElements extends AbstractCommand { private final static Pattern START_CDATA = Pattern.compile("<\\!\\[CDATA\\["); private final static Pattern END_CDATA = Pattern.compile("\\]\\]>"); + private final DOMLockController domLockController; private Element[] updates; private boolean coalesce = true; - public UpdateElements(boolean coalesce, Element[] updates) { + public UpdateElements(DOMLockController domLockController, boolean coalesce, Element[] updates) { + this.domLockController = domLockController; this.updates = updates; this.coalesce = coalesce; } @@ -57,25 +60,31 @@ public Command coalesceWithPrevious(UpdateElements updateElementsCommand) { ArrayList coallescedUpdates = new ArrayList(); Element[] previousUpdates = updateElementsCommand.updates; - - for (int i = 0; i < previousUpdates.length; i++) { - Element previousUpdate = previousUpdates[i]; - boolean overriden = false; - //test if any of the new updates is replacing the same element - for (int j = 0; j < updates.length; j++) { - Element update = updates[j]; - if (update.getAttribute("id").equals(previousUpdate.getAttribute("id"))) { - overriden = true; break; + domLockController.aquireDOMLock(); + try { + for (int i = 0; i < previousUpdates.length; i++) { + Element previousUpdate = previousUpdates[i]; + boolean overriden = false; + //test if any of the new updates is replacing the same element + for (int j = 0; j < updates.length; j++) { + Element update = updates[j]; + if (update.getAttribute("id").equals(previousUpdate.getAttribute("id"))) { + overriden = true; + break; + } } + //drop overriden updates + if (!overriden) { + coallescedUpdates.add(previousUpdate); + } } - //drop overriden updates - if (!overriden) { - coallescedUpdates.add(previousUpdate); - } + coallescedUpdates.addAll(Arrays.asList(updates)); + + return new UpdateElements(domLockController, coalesce, + (Element[]) coallescedUpdates.toArray(new Element[coallescedUpdates.size()])); + } finally { + domLockController.releaseDOMLock(); } - coallescedUpdates.addAll(Arrays.asList(updates)); - - return new UpdateElements(coalesce, (Element[]) coallescedUpdates.toArray(new Element[coallescedUpdates.size()])); } public Command coalesceWithNext(Command command) { @@ -121,41 +130,46 @@ } public void serializeTo(Writer writer) throws IOException { - writer.write(""); - for (int i = 0; i < updates.length; i++) { - Element update = updates[i]; - if (update == null) continue; - writer.write(""); + domLockController.aquireDOMLock(); + try { + writer.write(""); + for (int i = 0; i < updates.length; i++) { + Element update = updates[i]; + if (update == null) continue; + writer.write(""); - NamedNodeMap attributes = update.getAttributes(); - for (int j = 0; j < attributes.getLength(); j++) { - Attr attribute = (Attr) attributes.item(j); - writer.write(""); + NamedNodeMap attributes = update.getAttributes(); + for (int j = 0; j < attributes.getLength(); j++) { + Attr attribute = (Attr) attributes.item(j); + writer.write(""); + } else { + writer.write("\">"); + } + } + + String content = DOMUtils.childrenToString(update); + if ("".equals(content)) { + writer.write(""); } else { - writer.write("\">"); + writer.write(""); + writer.write(content); + writer.write("]]>"); } + writer.write(""); } - - String content = DOMUtils.childrenToString(update); - if ("".equals(content)) { - writer.write(""); - } else { - writer.write(""); - writer.write(content); - writer.write("]]>"); - } - writer.write(""); + writer.write(""); + } finally { + domLockController.releaseDOMLock(); } - writer.write(""); } } Index: util/DOMLockController.java =================================================================== --- util/DOMLockController.java (revision 0) +++ util/DOMLockController.java (revision 0) @@ -0,0 +1,7 @@ +package com.icesoft.util; + +public interface DOMLockController { + + void aquireDOMLock(); + void releaseDOMLock(); +} Property changes on: util\DOMLockController.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Author Date Id Revision