| /* |
| * 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.trinidadinternal.context; |
| |
| import java.awt.Color; |
| |
| import java.io.Serializable; |
| |
| import java.math.RoundingMode; |
| |
| import java.util.ArrayDeque; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TimeZone; |
| |
| import javax.faces.application.ProjectStage; |
| import javax.faces.component.NamingContainer; |
| import javax.faces.component.UIComponent; |
| import javax.faces.component.UIViewRoot; |
| import javax.faces.component.visit.VisitContext; |
| import javax.faces.context.ExternalContext; |
| import javax.faces.context.FacesContext; |
| import javax.faces.view.ViewDeclarationLanguage; |
| |
| import org.apache.myfaces.trinidad.change.ChangeManager; |
| import org.apache.myfaces.trinidad.change.NullChangeManager; |
| import org.apache.myfaces.trinidad.change.SessionChangeManager; |
| import org.apache.myfaces.trinidad.component.UIXComponent; |
| import org.apache.myfaces.trinidad.config.RegionManager; |
| import org.apache.myfaces.trinidad.context.AccessibilityProfile; |
| import org.apache.myfaces.trinidad.context.Agent; |
| import org.apache.myfaces.trinidad.context.DialogService; |
| import org.apache.myfaces.trinidad.context.PageFlowScopeProvider; |
| import org.apache.myfaces.trinidad.context.PageResolver; |
| import org.apache.myfaces.trinidad.context.PartialPageContext; |
| import org.apache.myfaces.trinidad.context.RenderingContext; |
| import org.apache.myfaces.trinidad.context.RequestContext; |
| import org.apache.myfaces.trinidad.logging.TrinidadLogger; |
| import org.apache.myfaces.trinidad.render.CoreRenderer; |
| import org.apache.myfaces.trinidad.util.ClassLoaderUtils; |
| import org.apache.myfaces.trinidad.util.ComponentUtils; |
| import org.apache.myfaces.trinidad.util.ExternalContextUtils; |
| import org.apache.myfaces.trinidad.util.TransientHolder; |
| import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor; |
| import org.apache.myfaces.trinidadinternal.agent.AgentFactory; |
| import org.apache.myfaces.trinidadinternal.agent.AgentFactoryImpl; |
| import org.apache.myfaces.trinidadinternal.agent.TrinidadAgentImpl; |
| import org.apache.myfaces.trinidadinternal.application.InternalViewHandlingStrategy; |
| import org.apache.myfaces.trinidadinternal.application.StateManagerImpl; |
| import org.apache.myfaces.trinidadinternal.el.FormatterMap; |
| import org.apache.myfaces.trinidadinternal.el.HelpProvider; |
| import org.apache.myfaces.trinidadinternal.el.OracleHelpProvider; |
| import org.apache.myfaces.trinidadinternal.metadata.RegionMetadata; |
| import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderKit; |
| import org.apache.myfaces.trinidadinternal.ui.expl.ColorPaletteUtils; |
| import org.apache.myfaces.trinidadinternal.util.nls.LocaleUtils; |
| import org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl; |
| |
| |
| /** |
| */ |
| public class RequestContextImpl extends RequestContext |
| { |
| static public final String LAUNCH_PARAMETERS = |
| "org.apache.myfaces.trinidad.PageFlowSourceParameters"; |
| |
| static public final String LAUNCH_VIEW = |
| "org.apache.myfaces.trinidad.PageFlowSourceView"; |
| |
| |
| public RequestContextImpl(RequestContextBean bean) |
| { |
| _bean = bean; |
| _dialogService = new DialogServiceImpl(this); |
| _partialTargets = new HashSet<String>(); |
| _componentStack = new ArrayDeque<UIComponent>(); |
| } |
| |
| public void init(ExternalContext request) |
| { |
| attach(); |
| } |
| |
| |
| @Override |
| public DialogService getDialogService() |
| { |
| return _dialogService; |
| } |
| |
| @Override |
| public PageResolver getPageResolver() |
| { |
| return _pageResolver; |
| } |
| |
| @Override |
| public PageFlowScopeProvider getPageFlowScopeProvider() |
| { |
| return _pageFlowScopeProvider; |
| } |
| |
| @Override |
| public Map<String, Object> getPageFlowScope() |
| { |
| return _pageFlowScopeProvider.getPageFlowScope(__getFacesContext()); |
| } |
| |
| |
| @Override |
| public void returnFromDialog(Object returnValue, Map<Object, Object> returnParameters) |
| { |
| boolean dialogIsInaccessible = |
| _dialogService.returnFromDialog(returnValue, returnParameters); |
| _pageFlowScopeProvider.popPageFlowScope(__getFacesContext(), |
| dialogIsInaccessible); |
| } |
| |
| /** |
| * Launch a dialog. |
| * @todo Don't save parameters for state-saving, page-flow scope, etc. |
| */ |
| @Override |
| public void launchDialog( |
| UIViewRoot dialogRoot, |
| Map<String, Object> dialogParameters, |
| UIComponent source, |
| boolean useWindow, |
| Map<String, Object> windowProperties) |
| { |
| _pageFlowScopeProvider.pushPageFlowScope(__getFacesContext(), |
| true); |
| _dialogService.launchDialog(dialogRoot, |
| dialogParameters, |
| source, |
| useWindow, |
| windowProperties); |
| } |
| |
| @Override |
| public UploadedFileProcessor getUploadedFileProcessor() |
| { |
| return (UploadedFileProcessor) |
| _bean.getProperty(RequestContextBean.UPLOADED_FILE_PROCESSOR_KEY); |
| } |
| |
| @Override |
| public Long getUploadedFileMaxMemory() |
| { |
| return (Long) _bean.getProperty(RequestContextBean.UPLOADED_FILE_MAX_MEMORY_KEY); |
| } |
| |
| @Override |
| public Long getUploadedFileMaxDiskSpace() |
| { |
| return (Long) _bean.getProperty(RequestContextBean.UPLOADED_FILE_MAX_DISK_SPACE_KEY); |
| } |
| |
| @Override |
| public Long getUploadedFileMaxFileSize() |
| { |
| return (Long) _bean.getProperty(RequestContextBean.UPLOADED_FILE_MAX_FILE_SIZE_KEY); |
| } |
| |
| @Override |
| public Long getUploadedFileMaxChunkSize() |
| { |
| return (Long) _bean.getProperty(RequestContextBean.UPLOADED_FILE_MAX_CHUNK_SIZE_KEY); |
| } |
| |
| @Override |
| public String getUploadedFileTempDir() |
| { |
| return (String) _bean.getProperty(RequestContextBean.UPLOADED_FILE_TEMP_DIR_KEY); |
| } |
| |
| |
| @Override |
| public boolean isPostback() |
| { |
| FacesContext context = __getFacesContext(); |
| // First, see if this is definitely not a postback request |
| if (!TrinidadPhaseListener.isPostback(context)) |
| return false; |
| |
| // Second, see if we are still on the original view root (which |
| // the PhaseListener's isPostback() method doesn't look at). |
| UIViewRoot originalViewRoot = (UIViewRoot) |
| context.getExternalContext().getRequestMap(). |
| get(TrinidadPhaseListener.INITIAL_VIEW_ROOT_KEY); |
| |
| // However, we only set the "originalViewRoot" during the afterPhase() |
| // of our PhaseListener; so, if it's null, then we have to asume |
| // that we have yet to even reach this code, as in, for example, |
| // an afterPhase() phase listener method for Restore View that happens |
| // to run before ours (which happens if it's registered *after* ours, |
| // because afterPhase() runs in inverse order). If so, there certainly |
| // hasn't been any navigation, so consider it a postback request. |
| if ((originalViewRoot != null) && |
| (originalViewRoot != context.getViewRoot())) |
| return false; |
| |
| return true; |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public boolean isPartialRequest(FacesContext context) |
| { |
| return context.getPartialViewContext().isAjaxRequest(); |
| } |
| |
| |
| @Override |
| public boolean isDebugOutput() |
| { |
| // FALSE is the default value... |
| boolean debugOutput = Boolean.TRUE.equals( |
| _bean.getProperty(RequestContextBean.DEBUG_OUTPUT_KEY)); |
| |
| FacesContext fc = FacesContext.getCurrentInstance(); |
| |
| if (fc.isProjectStage(ProjectStage.Production)) |
| { |
| // on production we always want FALSE, unless the |
| // user explicitly set the config to TRUE, but |
| // generate a WARNING message for that. |
| if (debugOutput) |
| { |
| _LOG.warning("DEBUG_OUTPUT_TRUE_IN_PRODUCTION_STAGE"); |
| return true; |
| } |
| |
| return false; |
| } |
| else |
| { |
| return debugOutput; |
| } |
| } |
| |
| @Override |
| public boolean isClientValidationDisabled() |
| { |
| return (ClientValidation.DISABLED == getClientValidation()); |
| } |
| |
| @Override |
| public String getOutputMode() |
| { |
| //=-= Scott O'Bryan =-= |
| // FIXME: Not real happy with this. We should find a way to get this into |
| // the bean. The bean is cached by the RequestContextFactory, and the |
| // Portlet mode needs to be assigned per request since it's possible to run |
| // a trinidad application from a servlet container and a portlet container |
| // at the same time. For now? Hey, it works. |
| |
| if(ExternalContextUtils.isPortlet(__getFacesContext().getExternalContext())) |
| { |
| return CoreRenderKit.OUTPUT_MODE_PORTLET; |
| } |
| return (String) _bean.getProperty(RequestContextBean.OUTPUT_MODE_KEY); |
| } |
| |
| @Override |
| public String getSkinFamily() |
| { |
| return (String) _bean.getProperty(RequestContextBean.SKIN_FAMILY_KEY); |
| } |
| |
| @Override |
| public String getSkinVersion() |
| { |
| return (String) _bean.getProperty(RequestContextBean.SKIN_VERSION_KEY); |
| } |
| |
| @Override |
| public Accessibility getAccessibilityMode() |
| { |
| String name = (String) _bean.getProperty( |
| RequestContextBean.ACCESSIBILITY_MODE_KEY); |
| |
| return _ACCESSIBILITY_NAMES.get(name); |
| } |
| |
| @Override |
| public AccessibilityProfile getAccessibilityProfile() |
| { |
| return (AccessibilityProfile) _bean.getProperty( |
| RequestContextBean.ACCESSIBILITY_PROFILE_KEY); |
| } |
| |
| @Override |
| public ClientValidation getClientValidation() |
| { |
| ClientValidation clientValidation = (ClientValidation) |
| _bean.getProperty(RequestContextBean.CLIENT_VALIDATION_KEY); |
| |
| if (clientValidation == null) |
| clientValidation = ClientValidation.INLINE; |
| |
| // Force use of ALERT validation (instead of INLINE) if using |
| // screen reader mode |
| if ((clientValidation == ClientValidation.INLINE) && |
| (getAccessibilityMode() == RequestContext.Accessibility.SCREEN_READER)) |
| clientValidation = ClientValidation.ALERT; |
| |
| return clientValidation; |
| } |
| |
| @Override |
| public boolean isAnimationEnabled() |
| { |
| return !Boolean.FALSE.equals(_bean.getProperty(RequestContextBean.ANIMATION_ENABLED_KEY)); |
| } |
| |
| @Override |
| public char getNumberGroupingSeparator() |
| { |
| |
| Object property = _bean.getProperty( |
| RequestContextBean.NUMBER_GROUPING_SEPARATOR_KEY); |
| char c = CoreRenderer.toChar(property); |
| if (c != CoreRenderer.CHAR_UNDEFINED) |
| return c; |
| |
| return (char) 0; |
| } |
| |
| @Override |
| public char getDecimalSeparator() |
| { |
| Object property = _bean.getProperty( |
| RequestContextBean.DECIMAL_SEPARATOR_KEY); |
| char c = CoreRenderer.toChar(property); |
| if (c != CoreRenderer.CHAR_UNDEFINED) |
| return c; |
| |
| return (char) 0; |
| } |
| |
| |
| @Override |
| public TimeZone getTimeZone() |
| { |
| TimeZone tz = (TimeZone) _bean.getProperty(RequestContextBean.TIME_ZONE_KEY); |
| if (tz != null) |
| return tz; |
| |
| // see bug 4960813 |
| return TimeZone.getDefault(); |
| // see bug 4960813. we can't guess the timezone in javascript: |
| |
| // UIXCookie cookie = _getUIXCookie(); |
| // if (cookie != null) |
| // { |
| // if (cookie.getTimeZone() != null) |
| // return cookie.getTimeZone(); |
| // } |
| |
| // return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @SuppressWarnings("unchecked") |
| @Override |
| public ChangeManager getChangeManager() |
| { |
| FacesContext context = __getFacesContext(); |
| Map<String, Object> appMap = context.getExternalContext().getApplicationMap(); |
| ChangeManager changeManager = _getHeldProperty(appMap, _CHANGE_MANAGER_KEY, ChangeManager.class); |
| |
| if (changeManager == null) |
| { |
| changeManager = _createChangeManager(); |
| |
| _setHeldProperty(appMap, _CHANGE_MANAGER_KEY, changeManager); |
| } |
| |
| return changeManager; |
| } |
| |
| private ChangeManager _createChangeManager() |
| { |
| FacesContext context = __getFacesContext(); |
| String changeManager = |
| context.getExternalContext().getInitParameter( |
| _CHANGE_PERSISTENCE_INIT_PARAM); |
| if (changeManager != null) |
| { |
| // Support the "session" token |
| if ("session".equalsIgnoreCase(changeManager)) |
| { |
| _LOG.info("HTTPSESSION_USED_FOR_CHANGE_PERSISTENCE"); |
| return new SessionChangeManager(); |
| } |
| // Otherwise, just assume its a class name. |
| else |
| { |
| return _createChangeManager(changeManager); |
| } |
| } |
| return new NullChangeManager(); |
| } |
| |
| /** |
| * Indirectly instantiate ChangeManager classes that have external runtime |
| * dependencies, so that we don't create link dependencies. |
| * @param className |
| * @return The ChangeManager instance |
| */ |
| private ChangeManager _createChangeManager( |
| String className) |
| { |
| try |
| { |
| Class<?> managerClass = ClassLoaderUtils.loadClass(className); |
| return (ChangeManager)managerClass.newInstance(); |
| } |
| catch (Throwable throwable) |
| { |
| _LOG.warning("CHANGE_MANAGER_CREATION_FAILED", className); |
| _LOG.warning(throwable); |
| return new NullChangeManager(); |
| } |
| } |
| |
| |
| @Override |
| public RegionManager getRegionManager() |
| { |
| FacesContext context = __getFacesContext(); |
| return RegionMetadata.getRegionMetadata(context); |
| } |
| |
| @Override |
| public String getCurrencyCode() |
| { |
| return (String) _bean.getProperty(RequestContextBean.CURRENCY_CODE_KEY); |
| } |
| |
| @Override |
| public String getOracleHelpServletUrl() |
| { |
| return (String) _bean.getProperty( |
| RequestContextBean.ORACLE_HELP_SERVLET_URL_KEY); |
| } |
| |
| @Override |
| public boolean isRightToLeft() |
| { |
| Boolean b = (Boolean) _bean.getProperty(RequestContextBean.RIGHT_TO_LEFT_KEY); |
| if (b != null) |
| return b.booleanValue(); |
| |
| FacesContext fContext = __getFacesContext(); |
| if ((fContext != null) && (fContext.getViewRoot() != null)) |
| { |
| Locale locale = fContext.getViewRoot().getLocale(); |
| return (LocaleUtils.getReadingDirectionForLocale(locale) == |
| LocaleUtils.DIRECTION_RIGHTTOLEFT); |
| } |
| |
| return false; |
| } |
| |
| @Override |
| public Locale getFormattingLocale() |
| { |
| Object o = _bean.getProperty(RequestContextBean.FORMATTING_LOCALE_KEY); |
| if (o == null) |
| return null; |
| |
| if (o instanceof Locale) |
| return (Locale) o; |
| |
| // Don't know how this would ever get here. ConfigParser should have set the key if |
| // formatting-locale was specified, or it is null. |
| if (o instanceof String) |
| o = ((String)o).replace('_', '-'); |
| return LocaleUtils.getLocaleForIANAString(o.toString()); |
| } |
| |
| |
| @Override |
| public Map<String, Object> getHelpTopic() |
| { |
| HelpProvider provider = _getHelpProvider(); |
| if (provider == null) |
| return null; |
| |
| return provider.getHelpTopicMap(); |
| } |
| |
| @Override |
| public Map<String, Object> getHelpSystem() |
| { |
| HelpProvider provider = _getHelpProvider(); |
| if (provider == null) |
| return null; |
| |
| return provider.getHelpSystemMap(); |
| } |
| |
| // |
| // Partial Page Rendering support |
| // |
| |
| @Override |
| public void addPartialTarget(UIComponent target) |
| { |
| FacesContext fContext = __getFacesContext(); |
| |
| RenderingContext afContext = RenderingContext.getCurrentInstance(); |
| |
| PartialPageContext pContext = null; |
| |
| if (afContext != null) |
| { |
| pContext = afContext.getPartialPageContext(); |
| } |
| |
| if (pContext == null) |
| { |
| pContext = new MockPartialPageContext(fContext); |
| } |
| |
| // delegate to UIXComponent to allow for components to influence the IDs that get added |
| UIXComponent.addPartialTarget(fContext, pContext, target); |
| } |
| |
| /** |
| * @see org.apache.myfaces.trinidad.context.RequestContext#addPartialTargets(javax.faces.component.UIComponent, java.lang.String[]) |
| */ |
| @Override |
| public void addPartialTargets(UIComponent from, String... targets) |
| { |
| if (targets == null) |
| { |
| return; |
| } |
| for (String target : targets) |
| { |
| UIComponent component = ComponentUtils.findRelativeComponent(from, target); |
| if (component != null) |
| { |
| addPartialTarget(component); |
| } |
| } |
| } |
| |
| /** |
| * Returns the set of partial targets related to a given UIComponent. |
| */ |
| @Override |
| public Set<UIComponent> getPartialTargets(UIComponent source) |
| { |
| HashSet<UIComponent> set = new HashSet<UIComponent>(); |
| _addPartialTargets(set, source); |
| return set; |
| } |
| |
| @Override |
| public void addPartialTriggerListeners |
| (UIComponent listener, |
| String[] triggers) |
| { |
| if ((listener == null) || (triggers == null)) |
| return; |
| |
| Map<UIComponent, Set<UIComponent>> pl = _getPartialListeners(); |
| |
| for (int i = 0; i < triggers.length; i++) |
| { |
| String trigger = triggers[i]; |
| |
| |
| UIComponent master = ComponentUtils.findRelativeComponent(listener, trigger); |
| |
| boolean deprecatedFind = false; |
| |
| if (master == null) |
| { |
| UIComponent from = listener; |
| // backward compatible code |
| // The old rule is "if the component is a naming container, search relative |
| // to the parent; otherwise, search relative to the component." |
| if (listener instanceof NamingContainer) |
| { |
| from = listener.getParent(); |
| master = ComponentUtils.findRelativeComponent(from, trigger); |
| deprecatedFind = true; |
| } |
| } |
| |
| if (master == null) |
| { |
| _LOG.fine("CANNOT_FIND_PARTIAL_TRIGGER", new Object[] {trigger, listener}); |
| } |
| else |
| { |
| // if we found this with the deprecated method, |
| // then warn the user to change their syntax. |
| if (deprecatedFind) |
| { |
| _LOG.warning("DEPRECATED_TRIGGER_SYNTAX", |
| new Object[] {trigger, listener}); |
| } |
| |
| // Get the set of listeners on this trigger and add this component. |
| Set<UIComponent> listeners = pl.get(master); |
| if (listeners == null) |
| { |
| listeners = new HashSet<UIComponent>(); |
| pl.put(master, listeners); |
| } |
| listeners.add(listener); |
| } |
| } |
| } |
| |
| @Override |
| public void partialUpdateNotify(UIComponent updated) |
| { |
| if (updated != null) |
| { |
| // Wildcards removed for now. If there's a demonstrated need for global |
| // triggers, reinstate this. |
| |
| // and always do global |
| // _addTargets(_GLOBAL_TRIGGER); |
| |
| // now do all listeners |
| _addTargets(updated, new HashSet<UIComponent>()); |
| } |
| } |
| |
| /** |
| * Get the clientIds of all components that have requested partial update |
| */ |
| public Iterator<String> getPartialTargets() |
| { |
| return _partialTargets.iterator(); |
| } |
| |
| /** |
| * Get the clientIds of all components that have been updated (If a component |
| * is listening on this component, it will add itself to the partialTargets |
| * list). |
| */ |
| public Set<String> getPartialUpdates() |
| { |
| return _partialTargets; |
| } |
| |
| @Override |
| public Map<String, List<Color>> getColorPalette() |
| { |
| return ColorPaletteUtils.getColorPaletteMap(); |
| } |
| |
| @Override |
| public Map<Object, Map<Object,String>> getFormatter() |
| { |
| return FormatterMap.sharedInstance(); |
| } |
| |
| @Override |
| public RoundingMode getRoundingMode() |
| { |
| RoundingMode mode = (RoundingMode) _bean.getProperty( |
| RequestContextBean.ROUNDING_MODE_KEY); |
| |
| return (mode); |
| } |
| |
| @Override |
| public int getTwoDigitYearStart() |
| { |
| Integer twoDigitYearStart = (Integer) _bean.getProperty( |
| RequestContextBean.TWO_DIGIT_YEAR_START); |
| |
| if (twoDigitYearStart != null) |
| return twoDigitYearStart.intValue(); |
| |
| return 1950; |
| } |
| |
| @Override |
| public Agent getAgent() |
| { |
| if (_agent == null) |
| { |
| Agent agent = _agentFactory.createAgent(__getFacesContext()); |
| // =-=AEW In theory, this does not need to be a TrinidadAgent |
| // That should only be necessary once we get to rendering... |
| // However, we're gonna have to turn it into one when it comes |
| // to rendering time, and our RenderingContext isn't doing this |
| // today |
| TrinidadAgentImpl fAgent = new TrinidadAgentImpl(__getFacesContext(),agent); |
| _agent = fAgent; |
| } |
| |
| return _agent; |
| } |
| |
| @Override |
| public Object saveComponent(UIComponent component) |
| { |
| return StateManagerImpl.saveComponentTree(__getFacesContext(), |
| component); |
| } |
| |
| @Override |
| public UIComponent restoreComponent(Object state) |
| throws ClassNotFoundException, |
| InstantiationException, |
| IllegalAccessException |
| { |
| return StateManagerImpl.restoreComponentTree(__getFacesContext(), |
| state); |
| } |
| |
| @Override |
| public boolean isInternalViewRequest(FacesContext context) |
| { |
| UIViewRoot root = context.getViewRoot(); |
| if (root == null) |
| return false; |
| |
| ViewDeclarationLanguage strategy = context.getApplication(). |
| getViewHandler().getViewDeclarationLanguage(context, root.getViewId()); |
| |
| return (strategy instanceof InternalViewHandlingStrategy); |
| } |
| |
| @Override |
| public Map<String, Object> getViewMap() |
| { |
| return getViewMap(true); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public Map<String, Object> getViewMap(boolean create) |
| { |
| // Note: replace this method body with a call to UIViewRoot.getViewMap(boolean) when |
| // Trinidad is upgraded to use JSF 2.0 |
| |
| FacesContext facesContext = FacesContext.getCurrentInstance(); |
| UIViewRoot viewRoot = facesContext.getViewRoot(); |
| Map<String, Object> viewMap = null; |
| |
| if (viewRoot != null) |
| { |
| Map<String, Object> attrs = viewRoot.getAttributes(); |
| |
| viewMap = (Map<String, Object>)attrs.get(_VIEW_MAP_KEY); |
| if (viewMap == null && create) |
| { |
| // Note, it is not valid to refer to the request context from outside of the request's |
| // thread. As such, synchronization and thread safety is not an issue here. |
| // This coincides with the JSF 2.0 code not using syncronization and using the non-thread |
| // safe HashMap. |
| viewMap = new HashMap<String, Object>(); |
| attrs.put(_VIEW_MAP_KEY, viewMap); |
| } |
| } |
| |
| return viewMap; |
| } |
| |
| @Override |
| public void pushCurrentComponent(FacesContext context, UIComponent component) |
| { |
| _componentStack.addFirst(component); |
| } |
| |
| @Override |
| public void popCurrentComponent(FacesContext context, UIComponent component) |
| { |
| UIComponent topComponent = _componentStack.poll(); |
| |
| // verify that we are removing the correct component |
| if (topComponent != component) |
| { |
| // put the component back |
| _componentStack.addFirst(component); |
| throw new IllegalStateException(); |
| } |
| } |
| |
| @Override |
| public UIComponent getCurrentComponent() |
| { |
| return _componentStack.peek(); |
| } |
| |
| void __setPageResolver(PageResolver pageResolver) |
| { |
| _pageResolver = pageResolver; |
| } |
| |
| void __setPageFlowScopeProvider(PageFlowScopeProvider pageFlowScopeProvider) |
| { |
| _pageFlowScopeProvider = pageFlowScopeProvider; |
| } |
| |
| int __getPageFlowScopeLifetime() |
| { |
| Integer lifetimeObj = (Integer) _bean.getProperty( |
| RequestContextBean.PAGE_FLOW_SCOPE_LIFETIME_KEY); |
| if (lifetimeObj == null) |
| return _DEFAULT_PAGE_FLOW_SCOPE_LIFETIME; |
| return lifetimeObj.intValue(); |
| } |
| |
| private void _addTargets( |
| UIComponent key, |
| Set<UIComponent> visitedComponents) |
| { |
| Map<UIComponent, Set<UIComponent>> pl = _getPartialListeners(); |
| Set<UIComponent> listeners = pl.get(key); |
| if (listeners != null && !listeners.isEmpty()) |
| { |
| // protect from infinite recursion by making sure we do not |
| // process the same component twice |
| if (!visitedComponents.add(key)) |
| { |
| return; |
| } |
| |
| for (UIComponent listener : listeners) |
| { |
| addPartialTarget(listener); |
| // This target will be re-rendered, re-render anything that's |
| // listening on it also. |
| _addTargets(listener, visitedComponents); |
| } |
| } |
| } |
| |
| private HelpProvider _getHelpProvider() |
| { |
| if (_provider == null) |
| { |
| String url = getOracleHelpServletUrl(); |
| if (url != null) |
| _provider = new OracleHelpProvider(url); |
| } |
| |
| return _provider; |
| } |
| |
| // |
| // Get the FacesContext. We used to cache the instance, but |
| // in some circumstances the RequestContext was getting reused |
| // across multiple FacesServlet invocations, so the caching |
| // was more trouble than it was worth. Re-enable some sort |
| // of caching if it proves a performance issue. |
| // |
| FacesContext __getFacesContext() |
| { |
| FacesContext fContext = FacesContext.getCurrentInstance(); |
| // If we haven't hit the FacesServlet yet, then the |
| // FacesContext won't be available yet - so go |
| // to the filter and ask for a pseudo-FacesContext |
| if (fContext == null) |
| { |
| fContext = TrinidadFilterImpl.getPseudoFacesContext(); |
| } |
| |
| return fContext; |
| } |
| |
| private Map<UIComponent, Set<UIComponent>> _getPartialListeners() |
| { |
| if (_partialListeners == null) |
| _partialListeners = new HashMap<UIComponent, Set<UIComponent>>(); |
| |
| return _partialListeners; |
| } |
| |
| // |
| // Recursively builds up the set of partial targets of |
| // a given component |
| // |
| private void _addPartialTargets( |
| Set<UIComponent> sofar, UIComponent from) |
| { |
| Map<UIComponent, Set<UIComponent>> pl = _getPartialListeners(); |
| Set<UIComponent> listeners = pl.get(from); |
| if (listeners == null) |
| return; |
| |
| for (UIComponent target : listeners) |
| { |
| // If we haven't encountered this target yet, add |
| // it, and continue recursively. |
| if (!sofar.contains(target)) |
| { |
| sofar.add(target); |
| _addPartialTargets(sofar, target); |
| } |
| } |
| } |
| |
| /** |
| * Convenience function for cached properties potentially held using a TransientHolder |
| * that hides the TransientHolder.getValue() step from the caller |
| * @param stateMap Map containing TransientHolders to retrieve value from |
| * @param key Key value/TransientHolder value is held under |
| * @param clazz Class of the value |
| * @return The value of the TransientHolder or <Code>null</code> if the TransientHolder doesn't |
| * exist or has the <code>null</code> value (which could happen if the TransientHolder has |
| * been Serialized) |
| */ |
| private static <S> S _getHeldProperty( |
| Map<String, ?> stateMap, |
| String key, |
| Class<S> clazz) |
| { |
| Object value = stateMap.get(key); |
| |
| if (value != null) |
| { |
| // if the value is already the right class, return it |
| if (clazz.isAssignableFrom(value.getClass())) |
| return (S)value; |
| else |
| { |
| // if the value is helpd in a TransientHolder, return it |
| if (value instanceof TransientHolder) |
| { |
| return ((TransientHolder<S>)value).getValue(); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| private static <S> void _setHeldProperty( |
| Map<String, Object> stateMap, |
| String key, |
| Object value) |
| { |
| if (!(value instanceof Serializable)) |
| value = TransientHolder.newTransientHolder(value); |
| |
| stateMap.put(key, value); |
| } |
| |
| private class MockPartialPageContext |
| extends PartialPageContext |
| { |
| private MockPartialPageContext(FacesContext facesContext) |
| { |
| } |
| |
| @Override |
| public boolean areAllTargetsProcessed() |
| { |
| // will never be true outside of rendering |
| return false; |
| } |
| |
| @Override |
| public boolean isPartialTargetRendered(String id) |
| { |
| // not valid outside of rendering |
| return false; |
| } |
| |
| @Override |
| public boolean isInsidePartialTarget() |
| { |
| // not valid outside of rendering |
| return false; |
| } |
| |
| public void addRenderedPartialTarget(String id) |
| { |
| // not valid outside of rendering |
| throw new UnsupportedOperationException(); |
| } |
| |
| public boolean isPartialTarget(String clientId) |
| { |
| return _partialTargets.contains(clientId); |
| } |
| |
| public boolean isPossiblePartialTarget(String componentId) |
| { |
| return _componentIds.contains(componentId); |
| } |
| |
| public Iterator<String> getPartialTargets() |
| { |
| return _partialTargets.iterator(); |
| } |
| |
| public void addPartialTarget(String clientId) |
| { |
| _partialTargets.add(clientId); |
| |
| int lastFragmentIndex = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR); |
| |
| String id = (lastFragmentIndex != -1) |
| ? clientId.substring(lastFragmentIndex + 1) |
| : clientId; |
| |
| _componentIds.add(id); |
| } |
| |
| public Iterator<String> getRenderedPartialTargets() |
| { |
| // not valid outside of rendering |
| Set<String> empty = Collections.emptySet(); |
| return empty.iterator(); |
| } |
| |
| public VisitContext getVisitContext() |
| { |
| // not valid outside of rendering |
| throw new UnsupportedOperationException(); |
| } |
| |
| private final HashSet<String> _componentIds = new HashSet<String>(); |
| } |
| |
| private RequestContextBean _bean; |
| private HelpProvider _provider; |
| private Map<UIComponent, Set<UIComponent>> _partialListeners; |
| private Set<String> _partialTargets; |
| private Agent _agent; |
| |
| private DialogServiceImpl _dialogService; |
| |
| private PageResolver _pageResolver; |
| private PageFlowScopeProvider _pageFlowScopeProvider; |
| private ArrayDeque<UIComponent> _componentStack; |
| |
| |
| //todo: get factory from configuration (else implementations have to provide their own RequestContext) |
| static private final AgentFactory _agentFactory = new AgentFactoryImpl(); |
| |
| // static private final Object _GLOBAL_TRIGGER = new Object(); |
| static private final int _DEFAULT_PAGE_FLOW_SCOPE_LIFETIME = 15; |
| static private final String _CHANGE_MANAGER_KEY = |
| "org.apache.myfaces.trinidadinternal.ChangeManager"; |
| static private final String _CHANGE_PERSISTENCE_INIT_PARAM = |
| "org.apache.myfaces.trinidad.CHANGE_PERSISTENCE"; |
| static private final String _VIEW_MAP_KEY = |
| RequestContextImpl.class.getName() + ".VIEW_MAP"; |
| |
| // A mapping from string names (as used in the config file) |
| // to accessibility objects |
| static private final Map<String, Accessibility> |
| _ACCESSIBILITY_NAMES = new HashMap<String, Accessibility>(); |
| |
| static |
| { |
| _ACCESSIBILITY_NAMES.put("default", Accessibility.DEFAULT); |
| _ACCESSIBILITY_NAMES.put("inaccessible", Accessibility.INACCESSIBLE); |
| _ACCESSIBILITY_NAMES.put("screenReader", Accessibility.SCREEN_READER); |
| } |
| |
| static private final TrinidadLogger _LOG = |
| TrinidadLogger.createTrinidadLogger(RequestContextImpl.class); |
| } |