You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2013/12/13 02:18:10 UTC
svn commit: r1550609 [2/5] - in /myfaces/core/trunk:
api/src/main/java/javax/faces/component/
api/src/test/java/javax/faces/component/
impl/src/main/java/org/apache/myfaces/application/
impl/src/main/java/org/apache/myfaces/config/ impl/src/main/java/o...
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java?rev=1550609&r1=1550608&r2=1550609&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java Fri Dec 13 01:18:08 2013
@@ -61,7 +61,11 @@ import org.apache.myfaces.shared.util.Cl
import org.apache.myfaces.shared.util.HashMapUtils;
import org.apache.myfaces.shared.util.WebConfigParamUtils;
import org.apache.myfaces.view.facelets.compiler.CheckDuplicateIdFaceletUtils;
+import org.apache.myfaces.view.facelets.pool.ViewEntry;
+import org.apache.myfaces.view.facelets.pool.ViewPool;
+import org.apache.myfaces.view.facelets.pool.ViewStructureMetadata;
import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
+import org.apache.myfaces.view.facelets.tag.jsf.FaceletState;
/**
* This class implements partial state saving feature when facelets
@@ -181,10 +185,21 @@ public class DefaultFaceletsStateManagem
private String _checkIdsProductionMode;
+ private MyfacesConfig _config;
+
+ private ViewPoolProcessor _viewPoolProcessor;
+
public DefaultFaceletsStateManagementStrategy ()
{
+ this(FacesContext.getCurrentInstance());
+ }
+
+ public DefaultFaceletsStateManagementStrategy (FacesContext context)
+ {
_vdlFactory = (ViewDeclarationLanguageFactory)
FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
+ _config = MyfacesConfig.getCurrentInstance(context.getExternalContext());
+ _viewPoolProcessor = ViewPoolProcessor.getInstance(context);
}
@SuppressWarnings("unchecked")
@@ -258,7 +273,7 @@ public class DefaultFaceletsStateManagem
}
context.setViewRoot (view);
-
+ boolean skipBuildView = false;
if (state != null && state[1] != null)
{
// Since JSF 2.2, UIViewRoot.restoreViewScopeState() must be called, but
@@ -266,13 +281,32 @@ public class DefaultFaceletsStateManagem
// id from this location. Remember in this point, PSS is enabled, so the
// code match with the assigment done in
// FaceletViewDeclarationLanguage.buildView()
+ states = (Map<String, Object>) state[1];
+ faceletViewState = UIComponentBase.restoreAttachedState(
+ context,states.get(ComponentSupport.FACELET_STATE_INSTANCE));
+ if (faceletViewState != null && _viewPoolProcessor != null)
+ {
+ ViewPool viewPool = _viewPoolProcessor.getViewPool(context, view);
+ if (viewPool != null)
+ {
+ ViewStructureMetadata viewMetadata = viewPool.retrieveDynamicViewStructureMetadata(
+ context, view, (FaceletState) faceletViewState);
+ if (viewMetadata != null)
+ {
+ ViewEntry entry = viewPool.popDynamicStructureView(context, view,
+ (FaceletState) faceletViewState);
+ if (entry != null)
+ {
+ skipBuildView = true;
+ _viewPoolProcessor.cloneAndRestoreView(context, view, entry, viewMetadata);
+ }
+ }
+ }
+ }
if (view.getId() == null)
{
view.setId(view.createUniqueId(context, null));
}
- states = (Map<String, Object>) state[1];
- faceletViewState = UIComponentBase.restoreAttachedState(
- context,states.get(ComponentSupport.FACELET_STATE_INSTANCE));
if (faceletViewState != null)
{
view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE, faceletViewState);
@@ -300,18 +334,21 @@ public class DefaultFaceletsStateManagem
// and then to true when postback. Since we need listeners registered to PostAddToViewEvent
// event to be handled, we should enable it again. For partial state saving we need this listeners
// be called from here and relocate components properly.
- try
- {
- context.setProcessingEvents (true);
- vdl.buildView (context, view);
- // In the latest code related to PostAddToView, it is
- // triggered no matter if it is applied on postback. It seems that MYFACES-2389,
- // TRINIDAD-1670 and TRINIDAD-1671 are related.
- suscribeListeners(view);
- }
- finally
+ if (!skipBuildView)
{
- context.setProcessingEvents (oldContextEventState);
+ try
+ {
+ context.setProcessingEvents (true);
+ vdl.buildView (context, view);
+ // In the latest code related to PostAddToView, it is
+ // triggered no matter if it is applied on postback. It seems that MYFACES-2389,
+ // TRINIDAD-1670 and TRINIDAD-1671 are related.
+ suscribeListeners(view);
+ }
+ finally
+ {
+ context.setProcessingEvents (oldContextEventState);
+ }
}
}
catch (Throwable e)
@@ -583,7 +620,11 @@ public class DefaultFaceletsStateManagem
// Create save state objects for every component.
- if (view.getAttributes().containsKey(COMPONENT_ADDED_AFTER_BUILD_VIEW))
+ boolean viewResetable = false;
+ int count = 0;
+ Object faceletViewState = null;
+ boolean saveViewFully = view.getAttributes().containsKey(COMPONENT_ADDED_AFTER_BUILD_VIEW);
+ if (saveViewFully)
{
ensureClearInitialState(view);
Object rlcStates = !context.getResourceLibraryContracts().isEmpty() ?
@@ -597,7 +638,7 @@ public class DefaultFaceletsStateManagem
{
states = new HashMap<String, Object>();
- Object faceletViewState = view.getAttributes().get(ComponentSupport.FACELET_STATE_INSTANCE);
+ faceletViewState = view.getAttributes().get(ComponentSupport.FACELET_STATE_INSTANCE);
if (faceletViewState != null)
{
((Map<String, Object>)states).put(ComponentSupport.FACELET_STATE_INSTANCE,
@@ -605,7 +646,20 @@ public class DefaultFaceletsStateManagem
//Do not save on UIViewRoot
view.getAttributes().remove(ComponentSupport.FACELET_STATE_INSTANCE);
}
- saveStateOnMapVisitTree(context,(Map<String,Object>) states, view);
+ if (_viewPoolProcessor != null &&
+ _viewPoolProcessor.isViewPoolEnabledForThisView(context, view))
+ {
+ SaveStateAndResetViewCallback cb = saveStateOnMapVisitTreeAndReset(
+ context,(Map<String,Object>) states, view,
+ Boolean.TRUE.equals(
+ context.getAttributes().get(ViewPoolProcessor.FORCE_HARD_RESET)));
+ viewResetable = cb.isViewResetable();
+ count = cb.getCount();
+ }
+ else
+ {
+ saveStateOnMapVisitTree(context,(Map<String,Object>) states, view);
+ }
if ( ((Map<String,Object>)states).isEmpty())
{
@@ -627,6 +681,21 @@ public class DefaultFaceletsStateManagem
serializedView = new Object[] { null, states };
}
+ //If view cache enabled store the view state into the pool
+ if (!saveViewFully && _viewPoolProcessor != null)
+ {
+ if (viewResetable)
+ {
+ _viewPoolProcessor.pushResetableView(
+ context, view, (FaceletState) faceletViewState);
+ }
+ else
+ {
+ _viewPoolProcessor.pushPartialView(
+ context, view, (FaceletState) faceletViewState, count);
+ }
+ }
+
context.getAttributes().put(SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
}
@@ -911,6 +980,304 @@ public class DefaultFaceletsStateManagem
}
}
+
+ private SaveStateAndResetViewCallback saveStateOnMapVisitTreeAndReset(final FacesContext facesContext,
+ final Map<String,Object> states, final UIViewRoot uiViewRoot, boolean forceHardReset)
+ {
+ facesContext.getAttributes().put(SKIP_ITERATION_HINT, Boolean.TRUE);
+ SaveStateAndResetViewCallback callback = new SaveStateAndResetViewCallback(
+ facesContext.getViewRoot(), states, forceHardReset);
+ if (forceHardReset)
+ {
+ uiViewRoot.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_HARD);
+ }
+ else
+ {
+ uiViewRoot.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_SOFT);
+ }
+ try
+ {
+ if (_viewPoolProcessor != null &&
+ !_viewPoolProcessor.isViewPoolEnabledForThisView(facesContext, uiViewRoot))
+ {
+ callback.setViewResetable(false);
+ }
+
+ // Check if the view has removed components. If that so, it
+ // means there is some manipulation over the component tree that
+ // can be rollback, so it is ok to set the view as resetable.
+ if (callback.isViewResetable())
+ {
+ List<String> removedIds = getClientIdsRemoved(uiViewRoot);
+ if (removedIds != null && !removedIds.isEmpty())
+ {
+ callback.setViewResetable(false);
+ }
+ }
+
+ try
+ {
+ uiViewRoot.visitTree( getVisitContextFactory().getVisitContext(
+ facesContext, null, VISIT_HINTS), callback);
+ }
+ finally
+ {
+ facesContext.getAttributes().remove(SKIP_ITERATION_HINT);
+ }
+
+ if (callback.isViewResetable() && callback.isRemoveAddedComponents())
+ {
+ List<String> clientIdsToRemove = getClientIdsAdded(uiViewRoot);
+
+ if (clientIdsToRemove != null)
+ {
+ // perf: clientIds are ArrayList: see method registerOnAddRemoveList(String)
+ for (int i = 0, size = clientIdsToRemove.size(); i < size; i++)
+ {
+ String clientId = clientIdsToRemove.get(i);
+ uiViewRoot.invokeOnComponent(facesContext, clientId, new RemoveComponentCallback());
+ }
+ }
+ }
+
+ Object state = uiViewRoot.saveState (facesContext);
+ if (state != null)
+ {
+ // Save by client ID into our map.
+ states.put (uiViewRoot.getClientId (facesContext), state);
+
+ //Hard reset (or reset and check state again)
+ Integer oldResetMode = (Integer) uiViewRoot.getAttributes().put(
+ ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY, ViewPoolProcessor.RESET_MODE_HARD);
+ state = uiViewRoot.saveState (facesContext);
+ uiViewRoot.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY, oldResetMode);
+ if (state != null)
+ {
+ callback.setViewResetable(false);
+ }
+ }
+ }
+ finally
+ {
+ uiViewRoot.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_OFF);
+ }
+ return callback;
+ }
+
+ private class SaveStateAndResetViewCallback implements VisitCallback
+ {
+ private final Map<String, Object> states;
+
+ private final UIViewRoot view;
+
+ private boolean viewResetable;
+
+ private boolean skipRoot;
+
+ private int count;
+
+ private boolean forceHardReset;
+
+ private boolean removeAddedComponents;
+
+ public SaveStateAndResetViewCallback(UIViewRoot view, Map<String, Object> states,
+ boolean forceHardReset)
+ {
+ this.states = states;
+ this.view = view;
+ this.viewResetable = true;
+ this.skipRoot = true;
+ this.count = 0;
+ this.forceHardReset = forceHardReset;
+ this.removeAddedComponents = false;
+ }
+
+ public VisitResult visit(VisitContext context, UIComponent target)
+ {
+ FacesContext facesContext = context.getFacesContext();
+ Object state;
+ this.count++;
+
+ if ((target == null) || target.isTransient())
+ {
+ // No need to bother with these components or their children.
+
+ return VisitResult.REJECT;
+ }
+
+ if (skipRoot && target instanceof UIViewRoot)
+ {
+ //UIViewRoot should be scanned at last.
+ skipRoot = false;
+ return VisitResult.ACCEPT;
+ }
+
+ ComponentState componentAddedAfterBuildView
+ = (ComponentState) target.getAttributes().get(COMPONENT_ADDED_AFTER_BUILD_VIEW);
+
+ //Note if UIViewRoot has this marker, JSF 1.2 like state saving is used.
+ if (componentAddedAfterBuildView != null && (target.getParent() != null))
+ {
+ //Set this view as not resetable.
+ //setViewResetable(false);
+ // Enable flag to remove added components later
+ setRemoveAddedComponents(true);
+ if (forceHardReset)
+ {
+ // The ideal is remove the added component here but visitTree does not support that
+ // kind of tree manipulation.
+ if (isViewResetable() &&
+ ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
+ {
+ setViewResetable(false);
+ }
+ // it is not important to save anything, skip
+ return VisitResult.REJECT;
+ }
+ if (ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
+ {
+ //If the view has removed components, set the view as non resetable
+ setViewResetable(false);
+ registerOnAddRemoveList(facesContext, target.getClientId(facesContext));
+ target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
+ }
+ else if (ComponentState.ADD.equals(componentAddedAfterBuildView))
+ {
+ registerOnAddList(facesContext, target.getClientId(facesContext));
+ target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
+ }
+ else if (ComponentState.ADDED.equals(componentAddedAfterBuildView))
+ {
+ // Later on the check of removed components we'll see if the view
+ // is resetable or not.
+ registerOnAddList(facesContext, target.getClientId(facesContext));
+ }
+ ensureClearInitialState(target);
+ //Save all required info to restore the subtree.
+ //This includes position, structure and state of subtree
+
+ int childIndex = target.getParent().getChildren().indexOf(target);
+ if (childIndex >= 0)
+ {
+ states.put(target.getClientId(facesContext), new AttachedFullStateWrapper(
+ new Object[]{
+ target.getParent().getClientId(facesContext),
+ null,
+ childIndex,
+ internalBuildTreeStructureToSave(target),
+ target.processSaveState(facesContext)}));
+ }
+ else
+ {
+ String facetName = null;
+ if (target.getParent().getFacetCount() > 0)
+ {
+ for (Map.Entry<String, UIComponent> entry : target.getParent().getFacets().entrySet())
+ {
+ if (target.equals(entry.getValue()))
+ {
+ facetName = entry.getKey();
+ break;
+ }
+ }
+ }
+ states.put(target.getClientId(facesContext),new AttachedFullStateWrapper(new Object[]{
+ target.getParent().getClientId(facesContext),
+ facetName,
+ null,
+ internalBuildTreeStructureToSave(target),
+ target.processSaveState(facesContext)}));
+ }
+ return VisitResult.REJECT;
+ }
+ else if (target.getParent() != null)
+ {
+ if (forceHardReset)
+ {
+ // force hard reset set reset move on top
+ state = target.saveState (facesContext);
+ if (state != null)
+ {
+ setViewResetable(false);
+ return VisitResult.REJECT;
+ }
+ }
+ else
+ {
+ state = target.saveState (facesContext);
+
+ if (state != null)
+ {
+ // Save by client ID into our map.
+ states.put (target.getClientId (facesContext), state);
+
+ if (isViewResetable())
+ {
+ //Hard reset (or reset and check state again)
+ Integer oldResetMode = (Integer) view.getAttributes().put(
+ ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_HARD);
+ state = target.saveState (facesContext);
+ view.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ oldResetMode);
+ if (state != null)
+ {
+ setViewResetable(false);
+ }
+ }
+ }
+ }
+
+ return VisitResult.ACCEPT;
+ }
+ else
+ {
+ //Only UIViewRoot has no parent in a component tree.
+ return VisitResult.ACCEPT;
+ }
+ }
+
+ /**
+ * @return the viewResetable
+ */
+ public boolean isViewResetable()
+ {
+ return viewResetable;
+ }
+
+ /**
+ * @param viewResetable the viewResetable to set
+ */
+ public void setViewResetable(boolean viewResetable)
+ {
+ this.viewResetable = viewResetable;
+ }
+
+ public int getCount()
+ {
+ return count;
+ }
+
+ /**
+ * @return the removeAddedComponents
+ */
+ public boolean isRemoveAddedComponents()
+ {
+ return removeAddedComponents;
+ }
+
+ /**
+ * @param removeAddedComponents the removeAddedComponents to set
+ */
+ public void setRemoveAddedComponents(boolean removeAddedComponents)
+ {
+ this.removeAddedComponents = removeAddedComponents;
+ }
+ }
+
protected void ensureClearInitialState(UIComponent c)
{
c.clearInitialState();
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=1550609&r1=1550608&r2=1550609&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Fri Dec 13 01:18:08 2013
@@ -90,6 +90,7 @@ import javax.faces.view.facelets.Facelet
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.ResourceResolver;
import javax.servlet.http.HttpServletResponse;
+import org.apache.myfaces.application.StateManagerImpl;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import org.apache.myfaces.config.RuntimeConfig;
@@ -125,6 +126,10 @@ import static org.apache.myfaces.view.fa
import org.apache.myfaces.view.facelets.compiler.FaceletsCompilerSupport;
import org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener;
import org.apache.myfaces.view.facelets.impl.SectionUniqueIdCounter;
+import org.apache.myfaces.view.facelets.pool.RestoreViewFromPoolResult;
+import org.apache.myfaces.view.facelets.pool.ViewEntry;
+import org.apache.myfaces.view.facelets.pool.ViewPool;
+import org.apache.myfaces.view.facelets.pool.ViewStructureMetadata;
import org.apache.myfaces.view.facelets.tag.composite.CreateDynamicCompositeComponentListener;
import org.apache.myfaces.view.facelets.tag.jsf.PartialMethodExpressionActionListener;
import org.apache.myfaces.view.facelets.tag.jsf.PartialMethodExpressionValidator;
@@ -283,18 +288,24 @@ public class FaceletViewDeclarationLangu
private List<String> _prefixWildcardKeys;
private FaceletsCompilerSupport _faceletsCompilerSupport;
+
+ private MyfacesConfig _config;
+
+ private ViewPoolProcessor _viewPoolProcessor;
/**
*
*/
public FaceletViewDeclarationLanguage(FacesContext context)
{
+ _config = MyfacesConfig.getCurrentInstance(context.getExternalContext());
initialize(context);
_strategy = new FaceletViewDeclarationLanguageStrategy();
}
public FaceletViewDeclarationLanguage(FacesContext context, ViewDeclarationLanguageStrategy strategy)
{
+ _config = MyfacesConfig.getCurrentInstance(context.getExternalContext());
initialize(context);
_strategy = strategy;
}
@@ -316,6 +327,28 @@ public class FaceletViewDeclarationLangu
return false;
}
+ private RestoreViewFromPoolResult tryRestoreViewFromCache(FacesContext context, UIViewRoot view)
+ {
+ if (_viewPoolProcessor != null)
+ {
+ ViewPool viewPool = _viewPoolProcessor.getViewPool(context, view);
+ if (viewPool != null)
+ {
+ ViewStructureMetadata metadata = viewPool.retrieveStaticViewStructureMetadata(context, view);
+ if (metadata != null)
+ {
+ ViewEntry entry = viewPool.popStaticOrPartialStructureView(context, view);
+ if (entry != null)
+ {
+ _viewPoolProcessor.cloneAndRestoreView(context, view, entry, metadata);
+ return entry.getResult();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
/**
* {@inheritDoc}
*/
@@ -356,7 +389,48 @@ public class FaceletViewDeclarationLangu
boolean usePartialStateSavingOnThisView = _usePartialStateSavingOnThisView(renderedViewId);
boolean refreshTransientBuild = (view.getChildCount() > 0);
boolean refreshTransientBuildOnPSS = (usePartialStateSavingOnThisView && _refreshTransientBuildOnPSS);
+ boolean refreshPartialView = false;
+ if (_viewPoolProcessor != null && !refreshTransientBuild)
+ {
+ RestoreViewFromPoolResult result = tryRestoreViewFromCache(context, view);
+ if (result != null)
+ {
+ // Since all transient stuff has been removed, add listeners that keep
+ // track of tree updates.
+ if (RestoreViewFromPoolResult.COMPLETE.equals(result))
+ {
+ if (!PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId()))
+ {
+ ((DefaultFaceletsStateManagementStrategy)
+ getStateManagementStrategy(context, view.getViewId())).
+ suscribeListeners(view);
+ }
+ // If the result is complete, the view restored here is static.
+ // static views can be marked as filled.
+ if (!refreshTransientBuildOnPSS)
+ {
+ // This option will be true on this cases:
+ // -pss is true and refresh is not active
+ setFilledView(context, view);
+ }
+ //At this point refreshTransientBuild = false && refreshTransientBuildOnPSS is true
+ else if (_refreshTransientBuildOnPSSAuto &&
+ !context.getAttributes().containsKey(CLEAN_TRANSIENT_BUILD_ON_RESTORE))
+ {
+ setFilledView(context, view);
+ }
+ return;
+ }
+ else
+ {
+ // We need to refresh a partial view.
+ refreshTransientBuild = true;
+ refreshPartialView = true;
+ }
+ }
+ }
+
if (usePartialStateSavingOnThisView)
{
// Before apply we need to make sure the current view has
@@ -371,7 +445,7 @@ public class FaceletViewDeclarationLangu
context.getAttributes().put(USING_PSS_ON_THIS_VIEW, Boolean.TRUE);
//Add a key to indicate ComponentTagHandlerDelegate to
//call UIComponent.markInitialState after it is populated
- if (!refreshTransientBuild)
+ if (!refreshTransientBuild || refreshPartialView)
{
context.getAttributes().put(StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
context.getAttributes().put(IS_BUILDING_INITIAL_STATE_KEY_ALIAS, Boolean.TRUE);
@@ -466,8 +540,14 @@ public class FaceletViewDeclarationLangu
// UIViewRoot.markInitialState() is not called because it does
// not have a facelet tag handler class that create it, instead
// new instances are created programatically.
- if (!refreshTransientBuild)
+ if (!refreshTransientBuild || refreshPartialView)
{
+ // Save the state
+ if (_viewPoolProcessor != null &&
+ _viewPoolProcessor.isViewPoolEnabledForThisView(context, view))
+ {
+ _viewPoolProcessor.storeViewStructureMetadata(context, view);
+ }
if (_markInitialStateWhenApplyBuildView)
{
if (!refreshTransientBuildOnPSS ||
@@ -1727,7 +1807,7 @@ public class FaceletViewDeclarationLangu
// the current view is not on javax.faces.FULL_STATE_SAVING_VIEW_IDS.
if (_partialStateSaving && _stateMgmtStrategy == null)
{
- _stateMgmtStrategy = new DefaultFaceletsStateManagementStrategy();
+ _stateMgmtStrategy = new DefaultFaceletsStateManagementStrategy(context);
}
return _usePartialStateSavingOnThisView(viewId) ? _stateMgmtStrategy : null;
@@ -1881,6 +1961,42 @@ public class FaceletViewDeclarationLangu
// saved yet.
stateMgr.saveView(context);
}
+ else
+ {
+ // GET case without any form that trigger state saving.
+ // Try to store it into cache.
+ if (_viewPoolProcessor != null &&
+ _viewPoolProcessor.isViewPoolEnabledForThisView(context, view))
+ {
+ ViewDeclarationLanguage vdl = context.getApplication().
+ getViewHandler().getViewDeclarationLanguage(
+ context, view.getViewId());
+
+ if (ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID.equals(
+ vdl.getId()))
+ {
+ StateManagementStrategy sms = vdl.getStateManagementStrategy(
+ context, view.getId());
+ if (sms != null)
+ {
+ context.getAttributes().put(ViewPoolProcessor.FORCE_HARD_RESET, Boolean.TRUE);
+
+ // Force indirectly to store the map in the cache
+ try
+ {
+ Object state = sms.saveView(context);
+ }
+ finally
+ {
+ context.getAttributes().remove(ViewPoolProcessor.FORCE_HARD_RESET);
+ }
+
+ // Clear the calculated value from the application map
+ context.getAttributes().remove(SERIALIZED_VIEW_REQUEST_ATTR);
+ }
+ }
+ }
+ }
}
finally
{
@@ -1902,6 +2018,9 @@ public class FaceletViewDeclarationLangu
handleRenderException(context, e);
}
}
+
+ private static final String SERIALIZED_VIEW_REQUEST_ATTR =
+ StateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
/**
* {@inheritDoc}
@@ -2355,6 +2474,8 @@ public class FaceletViewDeclarationLangu
eContext.getApplicationMap().put(
CACHED_COMPONENT_IDS, componentIdsCached);
}
+
+ _viewPoolProcessor = ViewPoolProcessor.getInstance(context);
log.finest("Initialization Successful");
}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ViewPoolProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ViewPoolProcessor.java?rev=1550609&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ViewPoolProcessor.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ViewPoolProcessor.java Fri Dec 13 01:18:08 2013
@@ -0,0 +1,1008 @@
+/*
+ * 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.view.facelets;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.faces.application.Application;
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.ProjectStage;
+import javax.faces.application.ResourceDependency;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+import javax.faces.view.StateManagementStrategy;
+import javax.faces.view.ViewDeclarationLanguage;
+import org.apache.myfaces.application.StateManagerImpl;
+import org.apache.myfaces.component.ComponentResourceContainer;
+import org.apache.myfaces.context.RequestViewContext;
+import org.apache.myfaces.context.RequestViewMetadata;
+import org.apache.myfaces.lifecycle.DefaultRestoreViewSupport;
+import org.apache.myfaces.lifecycle.RestoreViewSupport;
+import org.apache.myfaces.shared.util.WebConfigParamUtils;
+import org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl;
+import org.apache.myfaces.view.facelets.pool.ViewPool;
+import org.apache.myfaces.view.facelets.pool.ViewPoolFactory;
+import org.apache.myfaces.view.facelets.pool.ViewEntry;
+import org.apache.myfaces.view.facelets.pool.ViewStructureMetadata;
+import org.apache.myfaces.view.facelets.pool.impl.ViewPoolFactoryImpl;
+import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
+import org.apache.myfaces.view.facelets.tag.jsf.FaceletState;
+
+/**
+ * This class is reponsible for all processing tasks related to the view pool.
+ *
+ * For enable the pool only for a subset of your views, you can
+ * add an entry inside faces-config.xml file like this:
+ * <pre>
+ * {@code
+ * <faces-config-extension>
+ * <view-pool-mapping>
+ * <url-pattern>/*</url-pattern>
+ * <parameter>
+ * <name>org.apache.myfaces.VIEW_POOL_MAX_POOL_SIZE</name>
+ * <value>5</value>
+ * </parameter>
+ * </view-pool-mapping>
+ * </faces-config-extension>
+ * }
+ * </pre>
+ *
+ * @author Leonardo Uribe
+ */
+public class ViewPoolProcessor
+{
+ /**
+ * Used to hold the view pool processor instance on the application map.
+ * A ViewPoolProcessor is only accessible if the view pool has been
+ * enabled for the whole application (using a web config parameter) or
+ * partially (an <view-pool-mapping> entry inside <faces-config-extension>).
+ */
+ private final static String INSTANCE = "oam.ViewPoolProcessor";
+
+ /**
+ * UIViewRoot attribute to enable/disable the view for use pooling.
+ */
+ public final static String ENABLE_VIEW_POOL = "oamEnableViewPool";
+
+ /**
+ * Flag that indicates to the StateManagementStrategy that no state needs
+ * to be stored and we are using saveState() to dispose the view and store it
+ * into the pool directly.
+ */
+ public final static String FORCE_HARD_RESET = "oam.ViewPool.forceHardReset";
+
+ /**
+ * Flag to indicate that dispose this view on navigation is valid.
+ */
+ public final static String DISPOSE_VIEW_NAVIGATION = "oam.ViewPool.disposeViewOnNavigation";
+
+ /**
+ * Attribute of UIViewRoot that indicates if a soft (1) or hard(2)
+ * (reset and check) reset is required in the call to saveState().
+ */
+ public final static String RESET_SAVE_STATE_MODE_KEY ="oam.view.resetSaveStateMode";
+
+ /**
+ * Indicates no reset should be done on this state saving
+ */
+ public static final int RESET_MODE_OFF = 0;
+
+ /**
+ * Indicates a soft reset should be done when saveState(...) is performed,
+ * which means all transient state should be cleared but the delta state
+ * should not be destroyed in the process.
+ */
+ public static final int RESET_MODE_SOFT = 1;
+
+ /**
+ * Indicates a hard reset should be done when saveState(...) is performed,
+ * which means all transient and delta state should be cleared, destroying
+ * all existing state in the process. If something cannot be reseted, the
+ * state should return non null, so the algorithm can remove the component
+ * from the tree and mark the tree as partial (requires refresh before
+ * reuse).
+ */
+ public static final int RESET_MODE_HARD = 2;
+
+ /**
+ * Param used to indicate a "deferred navigation" needs to be done. To allow the view pool to
+ * dispose the view properly (and reuse it later), it is necessary to ensure the view is not
+ * being used at the moment. If the navigation call occur inside an action listener, the current
+ * view is being used and cannot be disposed (because it conflicts with hard/soft reset). This
+ * extension allows to call handleNavigation() before end invoke application phase, but after
+ * traverse the component tree.
+ */
+ public static final String INVOKE_DEFERRED_NAVIGATION = "oam.invoke.navigation";
+
+ private ViewPoolFactory viewPoolFactory;
+ private RestoreViewSupport restoreViewSupport;
+
+ public ViewPoolProcessor(FacesContext context)
+ {
+ viewPoolFactory = new ViewPoolFactoryImpl(context);
+ restoreViewSupport = new DefaultRestoreViewSupport(context);
+ }
+
+ public static ViewPoolProcessor getInstance(FacesContext context)
+ {
+ return (ViewPoolProcessor) context.getExternalContext().
+ getApplicationMap().get(INSTANCE);
+ }
+
+ /**
+ * This method should be called at startup to decide if a view processor should be
+ * provided or not to the runtime.
+ *
+ * @param context
+ */
+ public static void initialize(FacesContext context)
+ {
+ if (context.isProjectStage(ProjectStage.Production))
+ {
+ String elMode = WebConfigParamUtils.getStringInitParameter(
+ context.getExternalContext(),
+ FaceletCompositionContextImpl.INIT_PARAM_CACHE_EL_EXPRESSIONS,
+ ELExpressionCacheMode.noCache.name());
+ if (elMode.equals(ELExpressionCacheMode.alwaysRecompile.name()))
+ {
+ ViewPoolProcessor processor = new ViewPoolProcessor(context);
+ context.getExternalContext().
+ getApplicationMap().put(INSTANCE, processor);
+ }
+ else
+ {
+ Logger.getLogger(ViewPoolProcessor.class.getName()).log(
+ Level.INFO, FaceletCompositionContextImpl.INIT_PARAM_CACHE_EL_EXPRESSIONS +
+ " web config parameter is set to \"" + ( (elMode == null) ? "none" : elMode) +
+ "\". To enable view pooling this param"+
+ " must be set to \"alwaysRecompile\". View Pooling disabled.");
+ }
+ }
+ }
+
+ public ViewPool getViewPool(FacesContext context, UIViewRoot root)
+ {
+ if (root.isTransient())
+ {
+ // Stateless views cannot be pooled, because we are reusing
+ // state saving algorithm for that.
+ return null;
+ }
+ Boolean enableViewPool = (Boolean) root.getAttributes().get(ViewPoolProcessor.ENABLE_VIEW_POOL);
+ if (enableViewPool != null && !Boolean.TRUE.equals(enableViewPool))
+ {
+ // view pool not enabled for this view.
+ return null;
+ }
+ else
+ {
+ return viewPoolFactory.getViewPool(context, root);
+ }
+ }
+
+ public boolean isViewPoolEnabledForThisView(FacesContext context, UIViewRoot root)
+ {
+ if (root.isTransient())
+ {
+ // Stateless views cannot be pooled, because we are reusing
+ // state saving algorithm for that.
+ return false;
+ }
+ Boolean enableViewPool = (Boolean) root.getAttributes().get(ViewPoolProcessor.ENABLE_VIEW_POOL);
+ if (enableViewPool != null)
+ {
+ if (Boolean.TRUE.equals(enableViewPool))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ ViewPool viewPool = getViewPool(context, root);
+ if (viewPool != null)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isViewPoolStrategyAllowedForThisView(FacesContext context, UIViewRoot root)
+ {
+ // Check if the viewId is not null.
+ if (root.getViewId() == null)
+ {
+ return false;
+ }
+ if (root.isTransient())
+ {
+ // Stateless views cannot be pooled, because we are reusing
+ // state saving algorithm for that.
+ return false;
+ }
+
+ // Check if the view is enabled or not for use pooling
+ if (!isViewPoolEnabledForThisView(context, root))
+ {
+ return false;
+ }
+
+ // Check if the vdl is using PSS on this view (has a vdl and that vdl is facelets)
+ ViewDeclarationLanguage vdl = context.getApplication().getViewHandler().
+ getViewDeclarationLanguage(context, root.getViewId());
+ if (vdl == null)
+ {
+ return false;
+ }
+ else if (!ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID.equals(vdl.getId()))
+ {
+ return false;
+ }
+
+ if (vdl.getStateManagementStrategy(context, root.getViewId()) == null)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public void setViewPoolDisabledOnThisView(FacesContext context, UIViewRoot root, boolean value)
+ {
+ root.getAttributes().put(ViewPoolProcessor.ENABLE_VIEW_POOL, !value);
+ }
+
+ /**
+ * Takes the newView and restore the state taken as base the provided ViewEntry,
+ * and then move all child components from oldView to newView, to finally obtain
+ * a clean component tree.
+ *
+ * @param context
+ * @param newView
+ * @param entry
+ */
+ public void cloneAndRestoreView(FacesContext context, UIViewRoot newView,
+ ViewEntry entry, ViewStructureMetadata metadata)
+ {
+ UIViewRoot oldView = entry.getViewRoot();
+ // retrieveViewRootInitialState(context, oldView)
+ Object viewState = metadata.getViewRootState();
+ if (viewState == null)
+ {
+ // (Optional, it should be always metadata)
+ oldView.clearInitialState();
+ viewState = oldView.saveState(context);
+ }
+ boolean oldProcessingEvents = context.isProcessingEvents();
+ context.setProcessingEvents(false);
+ try
+ {
+ if (oldView.getFacetCount() > 0)
+ {
+ List<String> facetKeys = new ArrayList<String>();
+ facetKeys.addAll(oldView.getFacets().keySet());
+ for (String facetKey : facetKeys)
+ {
+ //context.setProcessingEvents(false);
+ UIComponent facet = oldView.getFacets().remove(facetKey);
+ //context.setProcessingEvents(true);
+ newView.getFacets().put(facetKey, facet);
+ }
+ }
+ if (oldView.getChildCount() > 0)
+ {
+ for (Iterator<UIComponent> it = oldView.getChildren().iterator(); it.hasNext();)
+ {
+ //context.setProcessingEvents(false);
+ UIComponent c = it.next();
+ it.remove();
+ //context.setProcessingEvents(true);
+ newView.getChildren().add(c);
+ }
+ }
+
+ // Restore the newView as saved just before markInitialState() call
+ newView.restoreState(context, viewState);
+ newView.markInitialState();
+
+ if (!PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId()))
+ {
+ // Restore bindings like in restore view phase, because in this case,
+ // bindings needs to be set (Application.createComponent is not called!).
+ restoreViewSupport.processComponentBinding(context, newView);
+ }
+
+ // Update request view metadata to ensure resource list is restored as when the
+ // view was built on the first time. This ensures correct calculation of added
+ // resources by dynamic behavior.
+ RequestViewContext rcv = RequestViewContext.getCurrentInstance(context, newView, false);
+ if (rcv != null)
+ {
+ rcv.setRequestViewMetadata(metadata.getRequestViewMetadata().cloneInstance());
+ }
+ else
+ {
+ RequestViewContext.setCurrentInstance(context, newView,
+ RequestViewContext.newInstance(metadata.getRequestViewMetadata().cloneInstance()));
+ }
+ }
+ finally
+ {
+ context.setProcessingEvents(oldProcessingEvents);
+ }
+ }
+
+ public void storeViewStructureMetadata(FacesContext context, UIViewRoot root)
+ {
+ ViewPool viewPool = getViewPool(context, root);
+ if (viewPool != null)
+ {
+ FaceletState faceletState = (FaceletState) root.getAttributes().get(
+ ComponentSupport.FACELET_STATE_INSTANCE);
+ boolean isDynamic = faceletState != null ? faceletState.isDynamic() : false;
+ if (!isDynamic)
+ {
+ viewPool.storeStaticViewStructureMetadata(context, root, faceletState);
+ }
+ else
+ {
+ viewPool.storeDynamicViewStructureMetadata(context, root, faceletState);
+ }
+ }
+ }
+
+ public ViewStructureMetadata retrieveViewStructureMetadata(FacesContext context,
+ UIViewRoot root)
+ {
+ ViewPool viewPool = getViewPool(context, root);
+ FaceletState faceletState = (FaceletState) root.getAttributes().get(
+ ComponentSupport.FACELET_STATE_INSTANCE);
+ boolean isDynamic = faceletState != null ? faceletState.isDynamic() : false;
+ if (!isDynamic)
+ {
+ return viewPool.retrieveStaticViewStructureMetadata(context, root);
+ }
+ else
+ {
+ return viewPool.retrieveDynamicViewStructureMetadata(context, root, faceletState);
+ }
+ }
+
+ public void pushResetableView(FacesContext context, UIViewRoot view, FaceletState faceletViewState)
+ {
+ ViewPool viewPool = getViewPool(context, view);
+ boolean isDynamic = faceletViewState != null ? faceletViewState.isDynamic() : false;
+ if (!isDynamic)
+ {
+ clearTransientAndNonFaceletComponentsForStaticView(context, view);
+ viewPool.pushStaticStructureView(context, view);
+ }
+ else
+ {
+ ViewStructureMetadata viewStructureMetadata = viewPool.retrieveDynamicViewStructureMetadata(
+ context, view, faceletViewState);
+ if (viewStructureMetadata != null)
+ {
+ clearTransientAndNonFaceletComponentsForDynamicView(context, view, viewStructureMetadata);
+ viewPool.pushDynamicStructureView(context, view, faceletViewState);
+ }
+ }
+ }
+
+ public void pushPartialView(FacesContext context, UIViewRoot view, FaceletState faceletViewState, int count)
+ {
+ ViewPool viewPool = getViewPool(context, view);
+
+ if (viewPool.isWorthToRecycleThisView(context, view))
+ {
+ ViewStructureMetadata viewStructureMetadata = null;
+ if (faceletViewState == null)
+ {
+ viewStructureMetadata = viewPool.retrieveStaticViewStructureMetadata(context, view);
+ }
+ else
+ {
+ viewStructureMetadata = viewPool.retrieveDynamicViewStructureMetadata(
+ context, view, faceletViewState);
+ }
+ if (viewStructureMetadata != null)
+ {
+ ClearPartialTreeContext ptc = new ClearPartialTreeContext();
+ // add partial structure view to the map.
+ clearTransientAndRemoveNonResetableComponents(context, ptc, view, viewStructureMetadata);
+ int reusableCount = ptc.getCount();
+ float factor = ((float)reusableCount) / ((float)count);
+ if (factor > 0.3f)
+ {
+ viewPool.pushPartialStructureView(context, view);
+ }
+ }
+ }
+ }
+
+ protected void clearTransientAndNonFaceletComponentsForStaticView(final FacesContext context,
+ final UIViewRoot root)
+ {
+ // In a static view, clear components that are both transient and non bound to any facelet tag handler
+ // is quite simple. Since the structure of the view is static, there is no need to check component resources.
+ clearTransientAndNonFaceletComponents(context, root);
+ }
+
+ public void clearTransientAndNonFaceletComponentsForDynamicView(final FacesContext context,
+ final UIViewRoot root, final ViewStructureMetadata viewStructureMetadata)
+ {
+ //Scan children
+ int childCount = root.getChildCount();
+ if (childCount > 0)
+ {
+ for (int i = 0; i < childCount; i++)
+ {
+ UIComponent child = root.getChildren().get(i);
+ if (child != null && child.isTransient() &&
+ child.getAttributes().get(ComponentSupport.MARK_CREATED) == null)
+ {
+ root.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ else
+ {
+ if (child.getChildCount() > 0 || !child.getFacets().isEmpty())
+ {
+ clearTransientAndNonFaceletComponents(context, child);
+ }
+ }
+ }
+ }
+
+ clearTransientAndNonFaceletComponentsForDynamicViewUIViewRootFacets(
+ context, root, viewStructureMetadata);
+ }
+
+ private void clearTransientAndNonFaceletComponentsForDynamicViewUIViewRootFacets(final FacesContext context,
+ final UIViewRoot root, ViewStructureMetadata viewStructureMetadata)
+ {
+
+ //Scan facets
+ if (root.getFacetCount() > 0)
+ {
+ Map<String, UIComponent> facets = root.getFacets();
+ for (Iterator<UIComponent> itr = facets.values().iterator(); itr.hasNext();)
+ {
+ UIComponent fc = itr.next();
+ if (fc != null && !(fc instanceof ComponentResourceContainer))
+ {
+ if ( fc.isTransient() &&
+ fc.getAttributes().get(ComponentSupport.MARK_CREATED) == null)
+ {
+ itr.remove();
+ }
+ else
+ {
+ if (fc.getChildCount() > 0 || !fc.getFacets().isEmpty())
+ {
+ clearTransientAndNonFaceletComponents(context, fc);
+ }
+ }
+ }
+ else if (fc != null)
+ {
+ // In a facet which is a ComponentResourceContainer instance,
+ // we need to check these two cases:
+ // 1. Resources relocated by facelets
+ // 2. Resources created by effect of a @ResourceDependency annotation
+ if (fc.getId() != null && fc.getId().startsWith("javax_faces_location_"))
+ {
+ String target = fc.getId().substring("javax_faces_location_".length());
+ Map<String, List<ResourceDependency>> addedResources =
+ viewStructureMetadata.getRequestViewMetadata().
+ getResourceDependencyAnnotations(context);
+ List<ResourceDependency> resourceDependencyList = (addedResources != null) ?
+ addedResources.get(target) : null;
+
+ clearComponentResourceContainer(context, fc, resourceDependencyList);
+ }
+ }
+ }
+ }
+ }
+
+ private void clearComponentResourceContainer(final FacesContext context, UIComponent component,
+ List<ResourceDependency> resourceDependencyList)
+ {
+ //Scan children
+ int childCount = component.getChildCount();
+ if (childCount > 0)
+ {
+ for (int i = 0; i < childCount; i++)
+ {
+ UIComponent child = component.getChildren().get(i);
+ String id = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED);
+ if (child != null && child.isTransient() &&
+ id == null)
+ {
+ //Remove both transient not facelets bound components
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ else if (id != null)
+ {
+ // If it has an id set, it is a facelet component resource.
+ // The refresh algorithm take care of the cleanup.
+ }
+ /*
+ else if (!child.isTransient() && id != null && !faceletResources.contains(id))
+ {
+ // check if the resource has a facelet tag in this "dynamic state", if not
+ // remove it. Really leave a component resource does not harm, but
+ // the objective is make this view as close as when if it is built as new.
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }*/
+ else
+ {
+ // Check if the component instance was created using a @ResourceDependency annotation
+ Object[] rdk = (Object[]) child.getAttributes().get(
+ RequestViewMetadata.RESOURCE_DEPENDENCY_KEY);
+ if (rdk != null)
+ {
+ boolean found = false;
+ String library = (String) rdk[0];
+ String name = (String) rdk[1];
+ if (resourceDependencyList != null)
+ {
+ for (ResourceDependency resource : resourceDependencyList)
+ {
+ if (library == null && resource.library() == null)
+ {
+ if (name != null && name.equals(resource.name()))
+ {
+ found = true;
+ break;
+ }
+ }
+ else
+ {
+ if (library != null && library.equals(resource.library()) &&
+ name != null && name.equals(resource.name()) )
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!found)
+ {
+ //Remove it, because for this dynamic state it it does not exists.
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ // If found just leave it.
+ }
+ else
+ {
+ if (child.getChildCount() > 0 || !child.getFacets().isEmpty())
+ {
+ clearTransientAndNonFaceletComponents(context, child);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear all transient components not created by facelets algorithm. In this way,
+ * we ensure the component tree does not have any changes done after markInitialState.
+ *
+ * @param context
+ * @param component
+ */
+ private void clearTransientAndNonFaceletComponents(final FacesContext context, final UIComponent component)
+ {
+ //Scan children
+ int childCount = component.getChildCount();
+ if (childCount > 0)
+ {
+ for (int i = 0; i < childCount; i++)
+ {
+ UIComponent child = component.getChildren().get(i);
+ if (child != null && child.isTransient() &&
+ child.getAttributes().get(ComponentSupport.MARK_CREATED) == null)
+ {
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ else
+ {
+ if (child.getChildCount() > 0 || !child.getFacets().isEmpty())
+ {
+ clearTransientAndNonFaceletComponents(context, child);
+ }
+ }
+ }
+ }
+
+ //Scan facets
+ if (component.getFacetCount() > 0)
+ {
+ Map<String, UIComponent> facets = component.getFacets();
+ for (Iterator<UIComponent> itr = facets.values().iterator(); itr.hasNext();)
+ {
+ UIComponent fc = itr.next();
+ if (fc != null && fc.isTransient() &&
+ fc.getAttributes().get(ComponentSupport.MARK_CREATED) == null)
+ {
+ itr.remove();
+ }
+ else
+ {
+ if (fc.getChildCount() > 0 || !fc.getFacets().isEmpty())
+ {
+ clearTransientAndNonFaceletComponents(context, fc);
+ }
+ }
+ }
+ }
+ }
+
+ private void clearTransientAndRemoveNonResetableComponents(final FacesContext context,
+ final ClearPartialTreeContext ptc, final UIViewRoot root,
+ ViewStructureMetadata viewStructureMetadata)
+ {
+ //Scan children
+ int childCount = root.getChildCount();
+
+ try
+ {
+ root.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_HARD);
+ if (childCount > 0)
+ {
+ for (int i = 0; i < childCount; i++)
+ {
+ UIComponent child = root.getChildren().get(i);
+ boolean containsFaceletId = child.getAttributes().containsKey(ComponentSupport.MARK_CREATED);
+ if (child != null && child.isTransient() && !containsFaceletId)
+ {
+ //Transient and not bound to facelets tag, remove it!.
+ root.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ else
+ {
+ if (child.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ //Dynamically added or moved, remove it!
+ root.getChildren().remove(i);
+ i--;
+ childCount--;
+
+ }
+ else if (containsFaceletId ||
+ child.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ // Bound to a facelet tag or created by facelets, we have two options:
+ // 1. If is not transient, check its state and try to clear it, if fails remove it
+ // 2. If is transient, assume stateless, continue.
+ if (!child.isTransient())
+ {
+ // Remember that hard reset is already enabled.
+ Object state = child.saveState(context);
+ if (state == null)
+ {
+ if (child.getChildCount() > 0 || !child.getFacets().isEmpty())
+ {
+ clearTransientAndRemoveNonResetableComponents(context, ptc, child);
+ }
+ ptc.incrementCount();
+ }
+ else
+ {
+ root.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ }
+ else
+ {
+ ptc.incrementCount();
+ }
+ }
+ else
+ {
+ // Non facelets component, remove it!.
+ root.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ }
+ }
+ }
+
+ clearTransientAndNonFaceletComponentsForDynamicViewUIViewRootFacets(
+ context, root, viewStructureMetadata);
+ }
+ finally
+ {
+ root.getAttributes().put(ViewPoolProcessor.RESET_SAVE_STATE_MODE_KEY,
+ ViewPoolProcessor.RESET_MODE_OFF);
+ }
+ }
+
+ private void clearTransientAndRemoveNonResetableComponents(final FacesContext context,
+ final ClearPartialTreeContext ptc, final UIComponent component)
+ {
+ //Scan children
+ int childCount = component.getChildCount();
+ if (childCount > 0)
+ {
+ for (int i = 0; i < childCount; i++)
+ {
+ UIComponent child = component.getChildren().get(i);
+ boolean containsFaceletId = child.getAttributes().containsKey(ComponentSupport.MARK_CREATED);
+ if (child != null && child.isTransient() && !containsFaceletId)
+ {
+ //Transient and not bound to facelets tag, remove it!.
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ else
+ {
+ if (child.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ //Dynamically added or moved, remove it!
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+
+ }
+ else if (containsFaceletId ||
+ child.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ // Bound to a facelet tag or created by facelets, we have two options:
+ // 1. If is not transient, check its state and try to clear it, if fails remove it
+ // 2. If is transient, assume stateless, continue.
+ if (!child.isTransient())
+ {
+ // Remember that hard reset is already enabled.
+ Object state = child.saveState(context);
+ if (state == null)
+ {
+ if (child.getChildCount() > 0 || !child.getFacets().isEmpty())
+ {
+ clearTransientAndRemoveNonResetableComponents(context, ptc, child);
+ }
+ ptc.incrementCount();
+ }
+ else
+ {
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ }
+ else
+ {
+ ptc.incrementCount();
+ }
+ }
+ else
+ {
+ // Non facelets component, remove it!.
+ component.getChildren().remove(i);
+ i--;
+ childCount--;
+ }
+ }
+ }
+ }
+
+ //Scan facets
+ if (component.getFacetCount() > 0)
+ {
+ Map<String, UIComponent> facets = component.getFacets();
+ for (Iterator<UIComponent> itr = facets.values().iterator(); itr.hasNext();)
+ {
+ UIComponent fc = itr.next();
+ boolean containsFaceletId = fc.getAttributes().containsKey(ComponentSupport.MARK_CREATED);
+ if (fc != null && fc.isTransient() && !containsFaceletId)
+ {
+ //Transient and not bound to facelets tag, remove it!.
+ itr.remove();
+ }
+ else
+ {
+ if (fc.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ //Dynamically added or moved, remove it!
+ itr.remove();
+
+ }
+ else if (containsFaceletId ||
+ fc.getAttributes().containsKey(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER))
+ {
+ // Bound to a facelet tag or created by facelets, we have two options:
+ // 1. If is not transient, check its state and try to clear it, if fails remove it
+ // 2. If is transient, assume stateless, continue.
+ if (!fc.isTransient())
+ {
+ // Remember that hard reset is already enabled.
+ Object state = fc.saveState(context);
+ if (state == null)
+ {
+ if (fc.getChildCount() > 0 || !fc.getFacets().isEmpty())
+ {
+ clearTransientAndRemoveNonResetableComponents(context, ptc, fc);
+ }
+ ptc.incrementCount();
+ }
+ else
+ {
+ itr.remove();
+ }
+ }
+ else
+ {
+ ptc.incrementCount();
+ }
+ }
+ else
+ {
+ // Non facelets component, remove it!.
+ itr.remove();
+ }
+ }
+ }
+ }
+ }
+
+ public void processDeferredNavigation(FacesContext facesContext)
+ {
+ Object[] command = (Object[]) facesContext.getAttributes().get(
+ ViewPoolProcessor.INVOKE_DEFERRED_NAVIGATION);
+ if (command != null)
+ {
+ try
+ {
+ facesContext.getAttributes().put(ViewPoolProcessor.DISPOSE_VIEW_NAVIGATION, Boolean.TRUE);
+ NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();
+ if (command.length == 3)
+ {
+ navigationHandler.handleNavigation(facesContext, (String) command[0], (String) command[1],
+ (String) command[2]);
+ }
+ else
+ {
+ navigationHandler.handleNavigation(facesContext, (String) command[0], (String) command[1]);
+ }
+ //Render Response if needed
+ facesContext.renderResponse();
+ facesContext.getAttributes().remove(ViewPoolProcessor.INVOKE_DEFERRED_NAVIGATION);
+ }
+ finally
+ {
+ facesContext.getAttributes().remove(ViewPoolProcessor.DISPOSE_VIEW_NAVIGATION);
+ }
+ }
+ }
+
+ private static final String SERIALIZED_VIEW_REQUEST_ATTR =
+ StateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
+
+ public void disposeView(FacesContext facesContext, UIViewRoot root)
+ {
+ if (root == null)
+ {
+ return;
+ }
+
+ String viewId = root.getViewId();
+ if (viewId == null)
+ {
+ return;
+ }
+ Application app = facesContext.getApplication();
+ if (app == null)
+ {
+ return;
+ }
+ ViewHandler viewHandler = app.getViewHandler();
+ if (viewHandler == null)
+ {
+ return;
+ }
+
+ if (Boolean.TRUE.equals(facesContext.getAttributes().get(ViewPoolProcessor.DISPOSE_VIEW_NAVIGATION)))
+ {
+ ViewDeclarationLanguage vdl = facesContext.getApplication().
+ getViewHandler().getViewDeclarationLanguage(
+ facesContext, root.getViewId());
+
+ if (vdl != null && ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID.equals(vdl.getId()))
+ {
+ StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, root.getId());
+ if (sms != null)
+ {
+ // Force indirectly to store the map in the pool
+ facesContext.getAttributes().put(ViewPoolProcessor.FORCE_HARD_RESET, Boolean.TRUE);
+
+ try
+ {
+ Object state = sms.saveView(facesContext);
+ }
+ finally
+ {
+ facesContext.getAttributes().remove(ViewPoolProcessor.FORCE_HARD_RESET);
+ }
+
+ // Clear the calculated value from the application map
+ facesContext.getAttributes().remove(SERIALIZED_VIEW_REQUEST_ATTR);
+ }
+ }
+ }
+ }
+
+ private static class ClearPartialTreeContext
+ {
+ private int count;
+
+ public ClearPartialTreeContext()
+ {
+ count = 0;
+ }
+
+ /**
+ * @return the count
+ */
+ public int getCount()
+ {
+ return count;
+ }
+
+ public int incrementCount()
+ {
+ return count++;
+ }
+ /**
+ * @param count the count to set
+ */
+ public void setCount(int count)
+ {
+ this.count = count;
+ }
+ }
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ViewPoolProcessor.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/RestoreViewFromPoolResult.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/RestoreViewFromPoolResult.java?rev=1550609&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/RestoreViewFromPoolResult.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/RestoreViewFromPoolResult.java Fri Dec 13 01:18:08 2013
@@ -0,0 +1,35 @@
+/*
+ * 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.view.facelets.pool;
+
+/**
+ *
+ */
+public enum RestoreViewFromPoolResult
+{
+ /**
+ * Indicate the view is ready to use.
+ */
+ COMPLETE,
+
+ /**
+ * Indicate the view requires to be refreshed by facelets algorithm.
+ */
+ REFRESH_REQUIRED
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/RestoreViewFromPoolResult.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewEntry.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewEntry.java?rev=1550609&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewEntry.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewEntry.java Fri Dec 13 01:18:08 2013
@@ -0,0 +1,52 @@
+/*
+ * 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.view.facelets.pool;
+
+import javax.faces.component.UIViewRoot;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public abstract class ViewEntry
+{
+ /**
+ * @return the viewRoot
+ */
+ public abstract UIViewRoot getViewRoot();
+
+ /**
+ * Execute all necessary steps to ensure further calls to
+ * getViewRoot() and getViewState() will return valid values.
+ * It returns true or false if the Entry is still active or not
+ *
+ */
+ public abstract boolean activate();
+
+ /**
+ * @return the result
+ */
+ public abstract RestoreViewFromPoolResult getResult();
+
+ /**
+ * @param result the result to set
+ */
+ public abstract void setResult(RestoreViewFromPoolResult result);
+
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPool.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPool.java?rev=1550609&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPool.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPool.java Fri Dec 13 01:18:08 2013
@@ -0,0 +1,129 @@
+/*
+ * 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.view.facelets.pool;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.view.facelets.tag.jsf.FaceletState;
+
+/**
+ * This class defines the necessary operations that a view pool should comply in
+ * order to be used by MyFaces.
+ *
+ * <p>A View Pool is a set of initialized views that are kept ready to use. The idea
+ * is reset and reuse views taking advantage of existing JSF 2.0 Partial State
+ * Saving algorithm with some small additions to component's saveState() method.
+ * </p>
+ * <p>This technique works by these reasons:
+ * </p>
+ * <ul>
+ * <li>A view is composed by many small objects that are created multiple times per
+ * each request, and the time spent creating these objects is usually larger than
+ * the time used to traverse the component tree.</li>
+ * <li>The structure of a view usually does not change over application lifetime.</li>
+ * <li>The "delta state" or in other words the elements that change in view are
+ * small compared with the elements that does not change.</li>
+ * <ul>
+ * <p>
+ * The implementation proposed uses a lock free view pool structure with soft or
+ * weak references. The lock free view pool ensures fast access and the soft or weak
+ * references ensured the garbage collection algorithm is not affected by the view
+ * pool.
+ * </p>
+ *
+ * @author Leonardo Uribe
+ */
+public abstract class ViewPool
+{
+ /**
+ * Defines the number of views to be hold per each view metadata definition.
+ * By default is 5.
+ *
+ * Usually a view is defined by its viewId, locale, renderKitId
+ * and active contracts. If a view shares the same values for these parameters
+ * belongs to the same group that can be pooled.
+ */
+ @JSFWebConfigParam(defaultValue="5", tags="performance")
+ public static final String INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE =
+ "org.apache.myfaces.VIEW_POOL_MAX_POOL_SIZE";
+ public static final int INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE_DEFAULT = 5;
+
+ /**
+ * Defines the limit of the views that cannot be reused partially.
+ */
+ @JSFWebConfigParam(defaultValue="2", tags="performance")
+ public static final String INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT =
+ "org.apache.myfaces.VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT";
+ public static final int INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT_DEFAULT = 2;
+
+ /**
+ * Defines the type of memory reference that is used to hold the view into memory. By
+ * default a "soft" reference is used.
+ */
+ @JSFWebConfigParam(defaultValue="soft", expectedValues="weak,soft", tags="performance")
+ public static final String INIT_PARAM_VIEW_POOL_ENTRY_MODE =
+ "org.apache.myfaces.VIEW_POOL_ENTRY_MODE";
+ public static final String ENTRY_MODE_SOFT = "soft";
+ public static final String ENTRY_MODE_WEAK = "weak";
+ public static final String INIT_PARAM_VIEW_POOL_ENTRY_MODE_DEFAULT = ENTRY_MODE_SOFT;
+
+ /**
+ * Defines if the view pool uses deferred navigation to recycle views when navigation
+ * is performed. The difference is a normal navigation is not done when the broadcast is
+ * done but at the end of invoke application phase.
+ */
+ @JSFWebConfigParam(defaultValue="false", expectedValues="true, false", tags="performance")
+ public static final String INIT_PARAM_VIEW_POOL_DEFERRED_NAVIGATION =
+ "org.apache.myfaces.VIEW_POOL_DEFERRED_NAVIGATION";
+
+ /**
+ * Indicate if the view pool uses deferred navigation.
+ *
+ * @return
+ */
+ public abstract boolean isDeferredNavigationEnabled();
+
+ public abstract void storeStaticViewStructureMetadata(FacesContext context,
+ UIViewRoot root, FaceletState faceletState);
+
+ public abstract ViewStructureMetadata retrieveStaticViewStructureMetadata(FacesContext context,
+ UIViewRoot root);
+
+ public abstract void pushStaticStructureView(FacesContext context, UIViewRoot root);
+
+ public abstract void pushPartialStructureView(FacesContext context, UIViewRoot root);
+
+ public abstract ViewEntry popStaticOrPartialStructureView(FacesContext context, UIViewRoot root);
+
+ public abstract boolean isWorthToRecycleThisView(FacesContext context, UIViewRoot root);
+
+ public abstract void storeDynamicViewStructureMetadata(FacesContext context,
+ UIViewRoot root, FaceletState faceletState);
+
+ public abstract ViewStructureMetadata retrieveDynamicViewStructureMetadata(FacesContext context,
+ UIViewRoot root, FaceletState faceletState);
+
+ public abstract void pushDynamicStructureView(FacesContext context, UIViewRoot root,
+ FaceletState faceletDynamicState);
+
+ public abstract ViewEntry popDynamicStructureView(FacesContext context, UIViewRoot root,
+ FaceletState faceletDynamicState);
+
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPool.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPoolFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPoolFactory.java?rev=1550609&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPoolFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPoolFactory.java Fri Dec 13 01:18:08 2013
@@ -0,0 +1,40 @@
+/*
+ * 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.view.facelets.pool;
+
+import javax.faces.FacesWrapper;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public abstract class ViewPoolFactory implements FacesWrapper<ViewPoolFactory>
+{
+
+ public abstract ViewPool getViewPool(FacesContext context,
+ UIViewRoot recyclableRoot);
+
+ public ViewPoolFactory getWrapped()
+ {
+ return null;
+ }
+
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/pool/ViewPoolFactory.java
------------------------------------------------------------------------------
svn:eol-style = native