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