blob: 980fea9bb55f4c020c627d4b1fc79cf7b00cfd69 [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.tobago.component;
import org.apache.myfaces.tobago.ajax.AjaxUtils;
import org.apache.myfaces.tobago.context.ClientProperties;
import org.apache.myfaces.tobago.internal.ajax.AjaxInternalUtils;
import org.apache.myfaces.tobago.internal.ajax.AjaxResponseRenderer;
import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
import org.apache.myfaces.tobago.internal.util.FacesContextUtils;
import org.apache.myfaces.tobago.util.ApplyRequestValuesCallback;
import org.apache.myfaces.tobago.util.ComponentUtils;
import org.apache.myfaces.tobago.util.FacesVersion;
import org.apache.myfaces.tobago.util.ProcessValidationsCallback;
import org.apache.myfaces.tobago.util.TobagoCallback;
import org.apache.myfaces.tobago.util.UpdateModelValuesCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.faces.FacesException;
import javax.faces.component.ContextCallback;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
/**
* @deprecated since 2.0.0
*/
@Deprecated
public class UIViewRoot extends javax.faces.component.UIViewRoot {
private static final Logger LOG = LoggerFactory.getLogger(UIViewRoot.class);
private static final TobagoCallback APPLY_REQUEST_VALUES_CALLBACK = new ApplyRequestValuesCallback();
private static final ContextCallback PROCESS_VALIDATION_CALLBACK = new ProcessValidationsCallback();
private static final ContextCallback UPDATE_MODEL_VALUES_CALLBACK = new UpdateModelValuesCallback();
private List<FacesEvent> events;
// XXX check if TOBAGO-811 is still an issue
// private int nextUniqueId;
@Override
public void setLocale(final Locale locale) {
super.setLocale(locale);
final ClientProperties clientProperties = ClientProperties.getInstance(getFacesContext());
clientProperties.setLocale(locale);
clientProperties.updateUserAgent(getFacesContext());
}
/*
// XXX check if TOBAGO-811 is still an issue
@Override
public Object saveState(FacesContext facesContext) {
if (FacesVersion.supports12()) {
return super.saveState(facesContext);
} else {
Object[] state = new Object[2];
state[0] = super.saveState(facesContext);
state[1] = nextUniqueId;
return state;
}
}
@Override
public void restoreState(FacesContext facesContext, Object o) {
if (FacesVersion.supports12()) {
super.restoreState(facesContext, o);
} else {
Object[] state = (Object[]) o;
super.restoreState(facesContext, state[0]);
nextUniqueId = (Integer) state[1];
}
}
@Override
public String createUniqueId() {
if (FacesVersion.supports12()) {
return super.createUniqueId();
} else {
ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext();
return extCtx.encodeNamespace(UNIQUE_ID_PREFIX + nextUniqueId++);
}
}
*/
// XXX begin of JSF 2.0 like code
public void broadcastEventsForPhase(final FacesContext context, final PhaseId phaseId) {
broadcastForPhase(phaseId);
if (context.getRenderResponse() || context.getResponseComplete()) {
clearEvents();
}
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
// The following code is copied from myfaces implementation!
// In suns jsf-api 1.1.01 are the events not cleared if renderResponse is true
// after processUpdates, seems to be a bug. This is fixed at least in
// Nightly Snapshot from 15.08.2005, but not in stable yet.
// Events are private member of UIViewRoot, so we have to copy anny code
// accessing them.
//
// TODO: remove if fixed in stable release! In 1.1_02 this seems to be fixed.
public void queueEvent(final FacesEvent event) {
if (event == null) {
throw new NullPointerException("event");
}
if (events == null) {
events = new ArrayList<FacesEvent>();
}
events.add(event);
}
private void broadcastForPhase(final PhaseId phaseId) {
if (events == null) {
return;
}
boolean abort = false;
final int phaseIdOrdinal = phaseId.getOrdinal();
for (final ListIterator<FacesEvent> listiterator = events.listIterator(); listiterator.hasNext();) {
final FacesEvent event = listiterator.next();
final int ordinal = event.getPhaseId().getOrdinal();
if (ordinal == PhaseId.ANY_PHASE.getOrdinal() || ordinal == phaseIdOrdinal) {
final UIComponent source = event.getComponent();
try {
source.broadcast(event);
} catch (final FacesException e) {
Throwable fe = e;
while (fe != null) {
if (fe instanceof AbortProcessingException) {
if (LOG.isTraceEnabled()) {
LOG.trace("AbortProcessingException caught!");
}
// abort event processing
// Page 3-30 of JSF 1.1 spec: "Throw an AbortProcessingException, to tell the JSF implementation
// that no further broadcast of this event, or any further events, should take place."
abort = true;
break;
}
fe = fe.getCause();
}
if (!abort) {
throw e;
} else {
break;
}
} finally {
try {
listiterator.remove();
} catch (final ConcurrentModificationException cme) {
final int eventIndex = listiterator.previousIndex();
events.remove(eventIndex);
//listiterator = events.listIterator();
}
}
}
}
if (abort) {
// TODO: abort processing of any event of any phase or just of any event of the current phase???
clearEvents();
}
}
private void clearEvents() {
events = null;
}
@Override
public void processDecodes(final FacesContext context) {
if (context == null) {
throw new NullPointerException("context");
}
final Map<String, UIComponent> ajaxComponents = AjaxInternalUtils.parseAndStoreComponents(context);
if (ajaxComponents != null) {
// first decode the page
final AbstractUIPage page = ComponentUtils.findPage(context);
page.decode(context);
page.markSubmittedForm(context);
FacesContextUtils.setAjax(context, true);
// decode the action if actionComponent not inside one of the ajaxComponents
// otherwise it is decoded there
decodeActionComponent(context, page, ajaxComponents);
// and all ajax components
for (final Map.Entry<String, UIComponent> entry : ajaxComponents.entrySet()) {
FacesContextUtils.setAjaxComponentId(context, entry.getKey());
invokeOnComponent(context, entry.getKey(), APPLY_REQUEST_VALUES_CALLBACK);
}
} else {
super.processDecodes(context);
}
broadcastForPhase(PhaseId.APPLY_REQUEST_VALUES);
if (context.getRenderResponse() || context.getResponseComplete()) {
clearEvents();
}
}
private void decodeActionComponent(final FacesContext facesContext, final AbstractUIPage page, final Map<String,
UIComponent> ajaxComponents) {
final String actionId = page.getActionId();
UIComponent actionComponent = null;
if (actionId != null) {
actionComponent = findComponent(actionId);
if (actionComponent == null && FacesVersion.supports20() && FacesVersion.isMyfaces()) {
final String bugActionId = actionId.replaceAll(":\\d+:", ":");
try {
actionComponent = findComponent(bugActionId);
//LOG.info("command = \"" + actionComponent + "\"", new Exception());
} catch (final Exception e) {
// ignore
}
}
}
if (actionComponent == null) {
return;
}
for (final UIComponent ajaxComponent : ajaxComponents.values()) {
UIComponent component = actionComponent;
while (component != null) {
if (component == ajaxComponent) {
return;
}
component = component.getParent();
}
}
invokeOnComponent(facesContext, actionId, APPLY_REQUEST_VALUES_CALLBACK);
}
@Override
public void processValidators(final FacesContext context) {
if (context == null) {
throw new NullPointerException("context");
}
final Map<String, UIComponent> ajaxComponents = AjaxInternalUtils.getAjaxComponents(context);
if (ajaxComponents != null) {
for (final Map.Entry<String, UIComponent> entry : ajaxComponents.entrySet()) {
FacesContextUtils.setAjaxComponentId(context, entry.getKey());
invokeOnComponent(context, entry.getKey(), PROCESS_VALIDATION_CALLBACK);
}
} else {
super.processValidators(context);
}
broadcastForPhase(PhaseId.PROCESS_VALIDATIONS);
if (context.getRenderResponse() || context.getResponseComplete()) {
clearEvents();
}
}
@Override
public void processUpdates(final FacesContext context) {
if (context == null) {
throw new NullPointerException("context");
}
final Map<String, UIComponent> ajaxComponents = AjaxInternalUtils.getAjaxComponents(context);
if (ajaxComponents != null) {
for (final Map.Entry<String, UIComponent> entry : ajaxComponents.entrySet()) {
invokeOnComponent(context, entry.getKey(), UPDATE_MODEL_VALUES_CALLBACK);
}
} else {
super.processUpdates(context);
}
broadcastForPhase(PhaseId.UPDATE_MODEL_VALUES);
if (context.getRenderResponse() || context.getResponseComplete()) {
clearEvents();
}
}
@Override
public void processApplication(final FacesContext context) {
if (context == null) {
throw new NullPointerException("context");
}
broadcastForPhase(PhaseId.INVOKE_APPLICATION);
if (context.getRenderResponse() || context.getResponseComplete()) {
clearEvents();
}
}
// XXX end of JSF 2.0 like code
@Override
public boolean getRendersChildren() {
if (AjaxUtils.isAjaxRequest(FacesContext.getCurrentInstance())) {
return true;
} else {
return super.getRendersChildren();
}
}
@Override
public void encodeChildren(final FacesContext context) throws IOException {
if (AjaxUtils.isAjaxRequest(context)) {
new AjaxResponseRenderer().renderResponse(context);
} else {
super.encodeChildren(context);
}
}
}