blob: 80cdc000454cb16df9c30ea87cadb9b24fab7cd0 [file] [log] [blame]
/*
* 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.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.view.facelets.Facelet;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.FaceletException;
import org.apache.myfaces.util.lang.AbstractAttributeMap;
import org.apache.myfaces.view.facelets.AbstractFacelet;
import org.apache.myfaces.view.facelets.AbstractFaceletContext;
import org.apache.myfaces.view.facelets.PageContext;
import org.apache.myfaces.view.facelets.TemplateClient;
import org.apache.myfaces.view.facelets.TemplateContext;
import org.apache.myfaces.view.facelets.TemplateManager;
/**
*
* @author Leonardo Uribe (latest modification by $Author$)
* @version $Revision$ $Date$
* @since 2.0.1
*/
public class TemplateContextImpl extends TemplateContext
{
/**
* This is a dummy instance
*/
private static final TemplateClient INITIAL_TEMPLATE_CLIENT = new InitialTemplateClient();
/**
* This is a dummy instance
*/
private static final PageContext INITIAL_PAGE_CONTEXT = new InitialPageContext();
private final List<TemplateManagerImpl> _clients;
private TemplateManager _compositeComponentClient;
private TemplateManagerImpl _lastClient;
private boolean _isCacheELExpressions;
private final TemplateClientAttributeMap _templateClientAttributeMap;
private final TemplateClientKnownParameterMap _templateClientKnownParameterMap;
public TemplateContextImpl()
{
super();
_clients = new ArrayList<>(4);
// Parameters registered using ui:param now are bound to template manager instances, because
// it should follow the same rules as template clients registered here. For example, to resolve
// params on nested ui:decorate and ui:composition the same rules applies than for ui:define and
// ui:insert. The simplest solution is add a template manager with a dummy template client and
// page context, so when a new context is added (like in a ui:include), all params registered go
// to this manager.
_clients.add(new TemplateManagerImpl(null, INITIAL_TEMPLATE_CLIENT, true, INITIAL_PAGE_CONTEXT));
_lastClient = _clients.get(0);
_isCacheELExpressions = true;
_templateClientAttributeMap = new TemplateClientAttributeMap();
_templateClientKnownParameterMap = new TemplateClientKnownParameterMap();
}
@Override
public TemplateManager popClient(final AbstractFaceletContext actx)
{
_lastClient = null;
return _clients.remove(0);
}
@Override
public void pushClient(final AbstractFaceletContext actx, final AbstractFacelet owner, final TemplateClient client)
{
_clients.add(0, new TemplateManagerImpl(owner, client, true, actx.getPageContext()));
_lastClient = _clients.get(0);
}
@Override
public TemplateManager popExtendedClient(final AbstractFaceletContext actx)
{
_lastClient = null;
return _clients.remove(_clients.size() - 1);
}
@Override
public void extendClient(final AbstractFaceletContext actx, final AbstractFacelet owner,
final TemplateClient client)
{
_clients.add(new TemplateManagerImpl(owner, client, false, actx.getPageContext()));
_lastClient = _clients.get(_clients.size() - 1);
}
@Override
public boolean includeDefinition(FaceletContext ctx, Facelet owner, UIComponent parent, String name)
throws IOException, FaceletException, FacesException, ELException
{
boolean found = false;
TemplateManager client;
for (int i = 0; i < _clients.size() && !found; i++)
{
client = _clients.get(i);
if (client.equals(owner))
{
continue;
}
found = client.apply(ctx, parent, name);
}
return found;
}
private final static class TemplateManagerImpl extends TemplateManager implements TemplateClient
{
private final AbstractFacelet _owner;
private final TemplateClient _target;
private final boolean _root;
private Set<String> _names;
private final PageContext _pageContext;
private Map<String, ValueExpression> _parameters = null;
private Set<String> _knownParameters;
public TemplateManagerImpl(AbstractFacelet owner, TemplateClient target,
boolean root, PageContext pageContext)
{
this._owner = owner;
this._target = target;
this._root = root;
this._pageContext = pageContext;
}
@Override
public boolean apply(FaceletContext ctx, UIComponent parent, String name)
throws IOException, FacesException, FaceletException,
ELException
{
String testName = (name != null) ? name : "facelets._NULL_DEF_";
if (this._owner == null)
{
return false;
}
if (this._names != null && this._names.contains(testName))
{
return false;
}
else
{
if (this._names == null)
{
this._names = new HashSet<>();
}
this._names.add(testName);
boolean found = false;
AbstractFaceletContext actx = new DefaultFaceletContext(
(DefaultFaceletContext) ctx, this._owner, false);
ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, actx);
try
{
actx.pushPageContext(this._pageContext);
found = this._target
.apply(actx,
parent, name);
}
finally
{
actx.popPageContext();
}
ctx.getFacesContext().getAttributes().put(FaceletContext.FACELET_CONTEXT_KEY, ctx);
this._names.remove(testName);
return found;
}
}
public Map<String, ValueExpression> getParametersMap()
{
if (_parameters == null)
{
_parameters = new HashMap<>();
}
return _parameters;
}
public boolean isParametersMapEmpty()
{
return _parameters == null ? true : _parameters.isEmpty();
}
public Set<String> getKnownParameters()
{
if (_knownParameters == null)
{
_knownParameters = new HashSet<>(4);
}
return _knownParameters;
}
public boolean isKnownParametersEmpty()
{
return _knownParameters == null ? true : _knownParameters.isEmpty();
}
@Override
public boolean equals(Object o)
{
if (this._owner != null)
{
return this._owner == o || this._target == o;
}
else
{
return this._target == o;
}
}
@Override
public int hashCode()
{
int result = _owner != null ? _owner.hashCode() : 0;
result = 31 * result + (_target != null ? _target.hashCode() : 0);
return result;
}
public boolean isRoot()
{
return this._root;
}
}
@Override
public TemplateManager getCompositeComponentClient()
{
return _compositeComponentClient;
}
@Override
public void setCompositeComponentClient(
TemplateManager compositeComponentClient)
{
_compositeComponentClient = compositeComponentClient;
}
@Override
public ValueExpression getParameter(String key)
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty() &&
client.getParametersMap().containsKey(key))
{
return client.getParametersMap().get(key);
}
}
return null;
}
@Override
public boolean containsParameter(String key)
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty() &&
client.getParametersMap().containsKey(key))
{
return true;
}
}
return false;
}
@Override
public void setParameter(String key, ValueExpression value)
{
if (_lastClient != null)
{
_lastClient.getParametersMap().put(key, value);
_lastClient.getKnownParameters().add(key);
}
}
@Override
public boolean isParameterEmpty()
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty())
{
return false;
}
}
return true;
}
@Override
public Map<String, ValueExpression> getParameterMap()
{
return _templateClientAttributeMap;
}
@Override
public boolean isKnownParametersEmpty()
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isKnownParametersEmpty())
{
return false;
}
}
return true;
}
@Override
public Set<String> getKnownParameters()
{
return _templateClientKnownParameterMap.keySet();
}
@Override
public boolean containsKnownParameter(String key)
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (client.getKnownParameters().contains(key))
{
return true;
}
}
return false;
}
@Override
public void addKnownParameters(String key)
{
if (_lastClient != null)
{
_lastClient.getKnownParameters().add(key);
}
}
private final class TemplateClientAttributeMap extends AbstractAttributeMap<ValueExpression>
{
public TemplateClientAttributeMap()
{
}
@Override
protected ValueExpression getAttribute(String key)
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty() &&
client.getParametersMap().containsKey(key))
{
return client.getParametersMap().get(key);
}
}
return null;
}
@Override
protected void setAttribute(String key, ValueExpression value)
{
throw new UnsupportedOperationException();
}
@Override
protected void removeAttribute(String key)
{
throw new UnsupportedOperationException();
}
@Override
protected Enumeration<String> getAttributeNames()
{
Set<String> attributeNames = new HashSet<>();
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty())
{
attributeNames.addAll(client.getParametersMap().keySet());
}
}
return new ParameterNameEnumeration(attributeNames.toArray(new String[attributeNames.size()]));
}
}
private static class ParameterNameEnumeration implements Enumeration<String>
{
private final String[] _parameterNames;
private final int _length;
private int _index;
public ParameterNameEnumeration(final String[] parameterNames)
{
_parameterNames = parameterNames;
_length = parameterNames.length;
}
@Override
public boolean hasMoreElements()
{
return _index < _length;
}
@Override
public String nextElement()
{
if (!hasMoreElements())
{
throw new NoSuchElementException();
}
return _parameterNames[_index++];
}
}
private final class TemplateClientKnownParameterMap extends AbstractAttributeMap<Boolean>
{
public TemplateClientKnownParameterMap()
{
}
@Override
protected Boolean getAttribute(String key)
{
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isKnownParametersEmpty() &&
client.getKnownParameters().contains(key))
{
return Boolean.TRUE;
}
}
return null;
}
@Override
protected void setAttribute(String key, Boolean value)
{
throw new UnsupportedOperationException();
}
@Override
protected void removeAttribute(String key)
{
throw new UnsupportedOperationException();
}
@Override
protected Enumeration<String> getAttributeNames()
{
Set<String> attributeNames = new HashSet<>();
TemplateManagerImpl client;
for (int i = 0; i < _clients.size(); i++)
{
client = _clients.get(i);
if (!client.isParametersMapEmpty())
{
attributeNames.addAll(client.getParametersMap().keySet());
}
}
return new ParameterNameEnumeration(attributeNames.toArray(new String[attributeNames.size()]));
}
}
/**
* This is just a dummy template client that does nothing that is added by default
* for each template context
*
*/
public static final class InitialTemplateClient implements TemplateClient
{
@Override
public boolean apply(FaceletContext ctx, UIComponent parent, String name)
throws IOException, FacesException, FaceletException, ELException
{
return false;
}
}
public static final class InitialPageContext extends PageContext
{
private boolean _isCacheELExpressions;
public InitialPageContext()
{
_isCacheELExpressions = true;
}
@Override
public Map<String, ValueExpression> getAttributes()
{
return Collections.emptyMap();
}
@Override
public int getAttributeCount()
{
return 0;
}
@Override
public boolean isAllowCacheELExpressions()
{
return _isCacheELExpressions;
}
@Override
public void setAllowCacheELExpressions(boolean cacheELExpressions)
{
_isCacheELExpressions = cacheELExpressions;
}
}
@Override
public boolean isAllowCacheELExpressions()
{
return _isCacheELExpressions;
}
@Override
public void setAllowCacheELExpressions(boolean cacheELExpressions)
{
_isCacheELExpressions = cacheELExpressions;
}
}