You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2009/06/10 14:44:26 UTC

svn commit: r783323 - in /myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component: ./ visit/ visit/FullVisitContext.java visit/PartialVisitContext.java visit/PartialVisitIdProxy.java visit/VisitContextFactoryImpl.java

Author: werpu
Date: Wed Jun 10 12:44:25 2009
New Revision: 783323

URL: http://svn.apache.org/viewvc?rev=783323&view=rev
Log:
https://issues.apache.org/jira/browse/MYFACES-2241
added the needed implementations for the vist context, next step is to enable it in our codebase

Added:
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java   (with props)
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java   (with props)
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java   (with props)
    myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java   (with props)

Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java?rev=783323&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java Wed Jun 10 12:44:25 2009
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2009 werpu.
+ * 
+ *  Licensed 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.
+ *  under the License.
+ */
+package org.apache.myfaces.component.visit;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * Another visit context for the full Tree Traversal!
+ *
+ * This visit context is rather simplistic because full tree
+ * traversal means always all components have to be visited!
+ * 
+ */
+public class FullVisitContext extends VisitContext {
+
+    FacesContext _facesContext;
+    Set<VisitHint> _hints;
+    Set<String> _ids;
+    Set<String> _visited = new HashSet<String>();
+
+    public FullVisitContext(FacesContext context, Set<VisitHint> hints) {
+        _facesContext = context;
+        _hints = (hints != null && hints.size() > 0) ?  EnumSet.copyOf(hints) : EnumSet.noneOf(VisitHint.class);
+    }
+
+    private void assertNamingContainer(UIComponent component) throws IllegalArgumentException {
+        if (!(component instanceof NamingContainer)) {
+            throw new IllegalArgumentException("Component  " + component.getClientId(_facesContext) + "must be of type NamingContainer");
+        }
+    }
+
+
+    @Override
+    public FacesContext getFacesContext() {
+        return _facesContext;
+    }
+
+    @Override
+    public Set<VisitHint> getHints() {
+        return _hints;
+    }
+
+    @Override
+    public Collection<String> getIdsToVisit() {
+        return VisitContext.ALL_IDS;
+    }
+
+    @Override
+    public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
+        assertNamingContainer(component);
+
+        return VisitContext.ALL_IDS;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback) {
+
+        String clientId = component.getClientId();
+
+        if (_visited.contains(clientId)) {
+            return VisitResult.ACCEPT;
+        } else {
+            _visited.add(clientId);
+            VisitResult retVal = callback.visit(this, component);
+            return retVal;
+        }
+
+    }
+}

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/FullVisitContext.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java?rev=783323&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java Wed Jun 10 12:44:25 2009
@@ -0,0 +1,160 @@
+/*
+ * 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.component.visit;
+
+import javax.faces.component.visit.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.context.FacesContext;
+
+public class PartialVisitContext extends VisitContext {
+
+    FacesContext _facesContext;
+    Set<VisitHint> _hints;
+    Set<String> _visited = new HashSet<String>();
+    PartialVisitIdProxy _idProxy = null;
+
+    public PartialVisitContext(FacesContext context, Collection<VisitHint> hints, Collection<String> ids) {
+        super();
+        _facesContext = context;
+        _hints =   (hints == null) ? EnumSet.noneOf(VisitHint.class):EnumSet.copyOf(hints);
+        _idProxy = new PartialVisitIdProxy(UINamingContainer.getSeparatorChar(context), ids);
+
+    }
+
+    private void assertNamingContainer(UIComponent component) throws IllegalArgumentException {
+        if (!(component instanceof NamingContainer)) {
+            throw new IllegalArgumentException("Component  " + component.getClientId(_facesContext) + "must be of type NamingContainer");
+        }
+    }
+
+    @Override
+    public FacesContext getFacesContext() {
+        return _facesContext;
+    }
+
+    @Override
+    public Set<VisitHint> getHints() {
+        return _hints;
+    }
+
+    /**
+     * Returns the collection of ids, as mutable collection!
+     * (In our case our internal PartialVisitProxy doing the heavy lifting)
+     */
+    @Override
+    public Collection<String> getIdsToVisit() {
+        return _idProxy;
+    }
+
+    /**
+     * returns all visit ids below the component given
+     * the component has to be a naming container!
+     * To speed things up we use an inverse cache,
+     * the component itself does not have to be in the visting list
+     * it can even be the body element!
+     *
+     *
+     * @param component
+     * @return
+     */
+    @Override
+    public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
+        assertNamingContainer(component);
+
+        //ok this is suboptimal, if we have forced ids we have to visit all components!
+        if (_idProxy.getForcedIds().size() > 0) {
+            return VisitContext.ALL_IDS;
+        }
+        //the alternative would be to descend into the subtrees
+        //but given the spec this method just gives hints whether
+        //we can shortcut or not!
+        //given this method might be called many times, it is not really justified to make a deep scan here
+        //it probably is better just to send an all have to be visited instead!
+
+
+        //an alternative might be to add the deep scan ids to the result set every time
+        //so that a component can shortcut if they are found!
+        //but this method is safer because the component then cannot make the assumption
+        //that a subtree id might be present while in reality it is not!
+        //the main issue here is simply that we cannot rely on the positions of our deep scan ids
+        //another one is performance, we have to treewalk here which is not optimal! especially
+        //since this method might be called many times
+
+        //I have to check this out if concatenation of the _deepScan Ids is possible in this case!
+        //if we can do it that we the speedup definitely will be bigger than
+
+        //also the hint system is ignored in our case, because UIComponent.isVisitable takes
+        //care of it!
+
+        Collection<String> retVal = new HashSet<String>(_idProxy.size());
+
+        String clientId = component.getClientId(_facesContext);
+        Collection<String> visitableComponents = _idProxy.getInverseCache().get(clientId);
+        if (visitableComponents == null || visitableComponents.size() == 0) {
+            return Collections.emptySet();
+        }
+
+        //not ideal still faster than influencing the visitableComponents data structure on the invoke side!
+        for (String componentId : visitableComponents) {
+            if (!_visited.contains(componentId)) {
+                retVal.add(componentId);
+            }
+        }
+
+        //this seems weird at the first look because it is not handled what has to happen
+        //if someone removed or adds an id from the outside, what happens is following
+        //that the caches are updated on the fly if this happens, the cache itself
+        //is not thread safe because, servlets normally can expect to be in a single thread
+        //context unless you work on singletons which is not the case in the case of a context!
+
+        return retVal;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback) {
+
+        String clientId = component.getClientId();
+        int idSize = _idProxy.size();
+
+
+        //premature termination condition
+        if (_visited.size() == idSize) {
+            return VisitResult.COMPLETE;
+        }
+
+        //accept in case of not processing or processed
+        boolean notProcessing = _visited.contains(clientId) ||
+                !_idProxy.contains(clientId);
+
+        if (notProcessing) {
+            return VisitResult.ACCEPT;
+        } else {
+            _visited.add(clientId);
+            VisitResult retVal = callback.visit(this, component);
+            return retVal;
+        }
+    }
+}

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitContext.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java?rev=783323&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java Wed Jun 10 12:44:25 2009
@@ -0,0 +1,240 @@
+/*
+ *  Licensed 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.
+ *  under the License.
+ */
+package org.apache.myfaces.component.visit;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.faces.context.FacesContext;
+
+/**
+ * Proxying class to speedup partial ids
+ */
+class PartialVisitIdProxy implements Set<String>{
+
+    FacesContext _facesContext;
+    Set<String> _ids;
+    Map<String, Collection<String>> _inverseCache = new HashMap<String, Collection<String>>();
+    Set<String> _forcedIds = new HashSet<String>();
+    char _separatorChar;
+
+    public Set<String> getIds() {
+        return _ids;
+    }
+
+    public Set<String> getForcedIds() {
+        return _forcedIds;
+    }
+
+    public Map<String, Collection<String>> getInverseCache() {
+        return _inverseCache;
+    }
+
+
+    public PartialVisitIdProxy(char separatorChar, Collection<String> ids) {
+        _ids = new HashSet<String>(ids);
+        _separatorChar = separatorChar;
+        initCaches();
+    }
+
+    private void removeFromCache(String clientId) {
+        char[] ids = clientId.toCharArray();
+        
+        StringBuilder finalContainer = new StringBuilder(clientId.length());
+        for (int cnt = 0; cnt < ids.length; cnt++) {
+            if (ids[cnt] == _separatorChar) {
+                String containerName = finalContainer.toString();
+                Collection<String> cacheEntry = _inverseCache.get(containerName);
+                if (cacheEntry == null) {
+                    continue;
+                }
+                if (cacheEntry.contains(clientId)) {
+                    cacheEntry.remove(clientId);
+                    if (cacheEntry.isEmpty()) {
+                        _inverseCache.remove(containerName);
+                    }
+                }
+            }
+            finalContainer.append(ids[cnt]);
+        }
+        _forcedIds.remove(clientId);
+    }
+
+
+
+
+
+   
+            
+
+
+    private boolean addToIndex(String clientId) {
+        
+        //we do not use a split here because we cannot rely on regexps in case of unknown chars
+        char[] ids = clientId.toCharArray();
+        StringBuilder finalContainer = new StringBuilder(clientId.length());
+        boolean added = false;
+        for (int cnt = 0; cnt < ids.length; cnt++) {
+            if (ids[cnt] == _separatorChar) {
+                String containerName = finalContainer.toString();
+                Collection<String> cacheEntry = _inverseCache.get(containerName);
+                if (cacheEntry == null) {
+                    cacheEntry = new HashSet<String>();
+                    _inverseCache.put(containerName, cacheEntry);
+                }
+                cacheEntry.add(clientId);
+                added = true;
+            } 
+            finalContainer.append(ids[cnt]);
+        }
+        //if not added add the id to the deep scan ids!
+        if (!added) {
+           return _forcedIds.add(clientId);
+        }
+        return true;
+    }
+
+    /**
+     * we have to initialize our caches
+     */
+    private void initCaches() {
+        _inverseCache.clear();
+        _forcedIds.clear();
+
+        for (String clientId : _ids) {
+            addToIndex(clientId);
+        }
+    }
+
+    @Override
+    public int size() {
+        return _ids.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return _ids.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return _ids.contains(o);
+    }
+
+    @Override
+    public Iterator<String> iterator() {
+        return new ProxyingIterator(_ids.iterator());
+    }
+
+    @Override
+    public Object[] toArray() {
+        return _ids.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return _ids.toArray(a);
+    }
+
+    @Override
+    public boolean add(String o) {
+        if(!_ids.add(o)) {
+            return false;
+        }
+        return addToIndex(o);
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        if(!_ids.remove((String)o)) {
+            return false;
+        }
+        removeFromCache((String)o);
+        return true;
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return _ids.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends String> c) {
+        for(String element: c) {
+            if(_ids.add(element)) {
+                addToIndex(element);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        _ids = new HashSet<String>();
+
+        for(Object element: c) {
+            _ids.add((String)element);
+        }
+       initCaches();
+        return true;
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        for(Object element: c) {
+            remove(element);
+        }
+        return true;
+    }
+
+    @Override
+    public void clear() {
+       _ids.clear();
+       _forcedIds.clear();
+       _inverseCache.clear();
+    }
+
+    class ProxyingIterator implements Iterator<String> {
+
+        Iterator<String> _delegate = null;
+        String _currentValue = null;
+
+        public ProxyingIterator(Iterator delegate) {
+            _delegate = delegate;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return _delegate.hasNext();
+        }
+
+        @Override
+        public String next() {
+            _currentValue =  _delegate.next();
+            return _currentValue;
+        }
+
+        @Override
+        public void remove() {
+           
+            _delegate.remove();
+            removeFromCache(_currentValue);
+        }
+
+    }
+}

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/PartialVisitIdProxy.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java?rev=783323&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java Wed Jun 10 12:44:25 2009
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 2009 werpu.
+ *
+ *  Licensed 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.
+ *  under the License.
+ */
+package org.apache.myfaces.component.visit;
+
+import java.util.Collection;
+import java.util.Set;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitContextFactory;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.context.FacesContext;
+
+/**
+ * Implementation of the VisitContextFactory!
+ */
+public class VisitContextFactoryImpl extends VisitContextFactory {
+
+    VisitContextFactory _wrapped = null;
+
+    public VisitContextFactoryImpl(VisitContextFactory wrapped) {
+        _wrapped = wrapped;
+    }
+
+    @Override
+    public VisitContextFactory getWrapped() {
+        return _wrapped;
+    }
+
+    @Override
+    public VisitContext getVisitContext(FacesContext context, Collection<String> ids, Set<VisitHint> hints) {
+        //since we are at the base here, we dont have to wrap for now, getWrapped will return null!
+        if (ids == null || ids.isEmpty()) {
+            return new FullVisitContext(context, hints);
+        } else {
+            return new PartialVisitContext(context, hints, ids);
+        }
+    }
+}

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/component/visit/VisitContextFactoryImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL