| /* |
| * 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.config; |
| |
| import java.io.IOException; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.concurrent.atomic.AtomicReference; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import javax.faces.context.ExternalContext; |
| import javax.faces.context.FacesContext; |
| |
| import javax.portlet.faces.annotation.ExcludeFromManagedRequestScope; |
| |
| import javax.servlet.ServletRequest; |
| import javax.servlet.ServletRequestWrapper; |
| import javax.servlet.http.HttpServletRequest; |
| |
| import org.apache.myfaces.trinidad.config.Configurator; |
| import org.apache.myfaces.trinidad.context.ExternalContextDecorator; |
| import org.apache.myfaces.trinidad.context.RequestContext; |
| import org.apache.myfaces.trinidad.context.RequestContextFactory; |
| import org.apache.myfaces.trinidad.context.WindowManager; |
| import org.apache.myfaces.trinidad.logging.TrinidadLogger; |
| import org.apache.myfaces.trinidad.skin.SkinFactory; |
| import org.apache.myfaces.trinidad.skin.SkinProvider; |
| import org.apache.myfaces.trinidad.util.ClassLoaderUtils; |
| import org.apache.myfaces.trinidad.util.ComponentReference; |
| import org.apache.myfaces.trinidad.util.ExternalContextUtils; |
| import org.apache.myfaces.trinidad.util.RequestStateMap; |
| import org.apache.myfaces.trinidad.util.RequestType; |
| import org.apache.myfaces.trinidadinternal.context.RequestContextFactoryImpl; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletCookieMap; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletRequestHeaderMap; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletRequestHeaderValuesMap; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletRequestMap; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletRequestParameterMap; |
| import org.apache.myfaces.trinidadinternal.context.external.ServletRequestParameterValuesMap; |
| import org.apache.myfaces.trinidadinternal.skin.SkinFactoryImpl; |
| import org.apache.myfaces.trinidadinternal.skin.provider.ExternalSkinProvider; |
| import org.apache.myfaces.trinidadinternal.skin.provider.SkinProviderRegistry; |
| import org.apache.myfaces.trinidadinternal.skin.provider.TrinidadSkinProvider; |
| |
| /** |
| * This is the implementation of the Trinidad's Global configurator. It provides the entry point for |
| * all other configurators. This class is responsible for enforcing the contract outlined by the |
| * Configurator abstract class, but allows a more "relaxed" implementation of the APIs called for by |
| * the Configurator class, making it more convenient to use ConfiguratorServices from within the |
| * Trinidad renderkit. Where appropriate, these differences will be documented for the benifit of |
| * the Trindad developer. |
| * |
| * @see org.apache.myfaces.trinidad.config.Configurator |
| * @version $Revision: daschnei_20131204_er17813713/3 $ $Date: 2014/01/21 13:53:38 $ |
| */ |
| public final class GlobalConfiguratorImpl |
| extends Configurator |
| { |
| /** |
| * Returns a GlobalConfigurator instance for the current context's class loader. The |
| * GlobalConfigurator is responsible for enforcing the contract on the other methods of this |
| * class. This means that if {@link #init(ExternalContext)} is called multiple times, the global |
| * configurator will call all subordinate configurators only once. |
| * |
| * Likewise, the GlobalConfigurator will return exceptions when the contract is expressly violated |
| * (like if {@link #getExternalContext(ExternalContext)} is called before a {{@link #beginRequest(ExternalContext)}. |
| * |
| * @return a GlobalConfigurator or <code>null</code> is one was unable to be obtained. |
| */ |
| |
| static public final void releaseInstance() |
| { |
| final ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| |
| if (loader == null) |
| { |
| _LOG.severe("CANNOT_FIND_CONTEXT_CLASS_LOADER"); |
| return; |
| } |
| synchronized (_CONFIGURATORS) |
| { |
| GlobalConfiguratorImpl config = _CONFIGURATORS.remove(loader); |
| _LOG.fine("GlobalConfigurator has been removed."); |
| |
| } |
| } |
| static public final GlobalConfiguratorImpl getInstance() |
| { |
| final ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| |
| if (loader == null) |
| { |
| _LOG.severe("CANNOT_FIND_CONTEXT_CLASS_LOADER"); |
| } |
| else |
| { |
| synchronized (_CONFIGURATORS) |
| { |
| GlobalConfiguratorImpl config = _CONFIGURATORS.get(loader); |
| if (config == null) |
| { |
| try |
| { |
| config = new GlobalConfiguratorImpl(); |
| _CONFIGURATORS.put(loader, config); |
| } |
| catch (final RuntimeException e) |
| { |
| // OC4J was not reporting these errors properly: |
| _LOG.severe(e); |
| throw e; |
| } |
| _LOG.fine("GlobalConfigurator has been created."); |
| } |
| return config; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns true if the request has not been stated for the current "virtual" |
| * request. In the servlet environment this will be true after |
| * {@link #beginRequest(ExternalContext)} is executed and before |
| * {@link #endRequest(ExternalContext)} is executed. This will generally |
| * happen once per request. In the Portlet Environment, the request must be |
| * be started and ended at the beginning and end of both the actionRequest |
| * and the RenderRequest. |
| * |
| * @param ec |
| * @return |
| */ |
| static public boolean isRequestStarted(ExternalContext ec) |
| { |
| return (RequestStateMap.getInstance(ec).get(_REQUEST_TYPE) != null); |
| } |
| |
| /** |
| * Returns "true" if the services should be considered enabled or disabled. |
| * |
| * @param ec |
| * @return |
| */ |
| static private final boolean _isDisabled(final ExternalContext ec) |
| { |
| final Boolean inRequest = (Boolean) RequestStateMap.getInstance(ec).get(_IN_REQUEST); |
| |
| if (inRequest == null) |
| { |
| return isConfiguratorServiceDisabled(ec); |
| } |
| else |
| { |
| final boolean disabled = inRequest.booleanValue(); |
| if (disabled != isConfiguratorServiceDisabled(ec)) |
| { |
| _LOG.warning("Configurator services were disabled after beginRequest was executed. Cannot disable configurator services"); |
| } |
| |
| return disabled; |
| } |
| } |
| |
| /** |
| * Private default constructor. Right now this class is not serializable. If serialization is |
| * required, we may wish to make this public. We really don't want people using this though. |
| */ |
| private GlobalConfiguratorImpl() |
| { |
| } |
| |
| /** |
| * Executes the beginRequest methods of all of the configurator services. This method will also |
| * initizlize the configurator if it has not already been initialized, so there may be no need to |
| * call the {@link #init(ExternalContext)} method directly. |
| * |
| * This method also ensures that the requestContext is attached before the beginRequest methods |
| * are called, so there is no reason to initialize the request context before calling this method. |
| * In portal environments, it is important to execute this method once for each Portlet action and |
| * render request so that the requestContext may be properly initialized even though the |
| * underlying services will be called only once per physical request. |
| * |
| * @param ec the externalContext to use to begin the request. |
| * |
| * @see Configurator#beginRequest(javax.faces.context.ExternalContext) |
| */ |
| @SuppressWarnings("unchecked") // TODO: remove this for Faces 1.2 |
| @Override |
| public void beginRequest(ExternalContext ec) |
| { |
| // asserts for debug which disappear in production |
| assert ec != null; |
| RequestStateMap state = RequestStateMap.getInstance(ec); |
| RequestType requestType = (RequestType) state.get(_REQUEST_TYPE); |
| |
| // Do per-virtual request stuff |
| if (requestType == null) |
| { |
| // RequestType may change in a portal environment. Make sure it's set up to enforce the |
| // contracts |
| requestType = ExternalContextUtils.getRequestType(ec); |
| RequestStateMap.getInstance(ec).put(_REQUEST_TYPE, requestType); |
| |
| // By contract, Configurators beginRequest is only called once per physical request. |
| // The globalConfigurator may be called multiple times, however, so we need to enforce |
| // the contract. |
| if (!_isDisabled(ec)) |
| { |
| // If this hasn't been initialized then please initialize |
| if (!_initialized.get()) |
| { |
| init(ec); |
| } |
| |
| _attachRequestContext(ec); |
| |
| if (state.get(_IN_REQUEST) == null) |
| { |
| // Allow WindowManager to perform some processing at the beginning of request and optionally complete the response |
| if (!Boolean.TRUE.equals(state.get(_CONFIGURATORS_ABORTED))) |
| { |
| if (_beginWindowManagerRequest(ec)) |
| { |
| _startConfiguratorServiceRequest(ec); |
| } |
| else |
| { |
| FacesContext.getCurrentInstance().responseComplete(); |
| state.put(_CONFIGURATORS_ABORTED, Boolean.TRUE); |
| } |
| } |
| } |
| } |
| else |
| { |
| _LOG.fine("GlobalConfigurator: Configurators have been disabled for this request."); |
| } |
| } |
| else if (!requestType.equals(ExternalContextUtils.getRequestType(ec))) |
| { |
| // This will happen if the actionRequest was not ended before dispatching to the render |
| // request |
| throw new IllegalStateException("The previous action request was not ended."); |
| } |
| else |
| { |
| _LOG.fine("BeginRequest called multiple times for this request"); |
| } |
| } |
| |
| /** |
| * Cleans up the current configurator. This will execute the destroy method on all of the |
| * configurator services. Generally this will be called by Trinidad's context listener when the |
| * context is destroyed, but it may be used manually to allow the configurator to be |
| * re-initialized. |
| * |
| * Calling this method while the configurator is not initialized will not re-execute the destroy |
| * methods on the services. |
| * |
| * @see org.apache.myfaces.trinidad.config.Configurator#destroy() |
| */ |
| @Override |
| public void destroy() |
| { |
| |
| if (_initialized.get()) |
| { |
| try |
| { |
| //Forces atomic operations with init. If we are in the middle of an init or another destroy, we'll |
| //wait on this lock until our operations are complete. We then have to recheck our initialized state. |
| |
| _initLock.lock(); |
| if (_initialized.get()) |
| { |
| for (final Configurator config: _services) |
| { |
| try |
| { |
| config.destroy(); |
| } |
| catch (final Throwable t) |
| { |
| // we always want to continue to destroy things, so log errors and continue |
| _LOG.severe(t); |
| } |
| } |
| _services = null; |
| _initialized.set(false); |
| } |
| } |
| finally |
| { |
| //release any managed threadlocals that may have been used durring destroy |
| _releaseManagedThreadLocals(); |
| _initLock.unlock(); |
| } |
| } |
| } |
| |
| /** |
| * Ends the currently begun request. It is important to note that this should be executed only |
| * once per physical request. |
| * |
| * @see org.apache.myfaces.trinidad.config.Configurator#endRequest(javax.faces.context.ExternalContext) |
| */ |
| @Override |
| public void endRequest(ExternalContext ec) |
| { |
| RequestStateMap state = RequestStateMap.getInstance(ec); |
| |
| // do per virtual-request stuff |
| if (state.get(_REQUEST_TYPE) != null) |
| { |
| try |
| { |
| _endRequest(ec, state); |
| } |
| finally |
| { |
| state.remove(_REQUEST_TYPE); |
| } |
| } |
| } |
| |
| /** |
| * Returns an externalContext for this configurator and all of the configurator services. If this |
| * method is executed before {@link #beginRequest(ExternalContext)} then this method will call |
| * beginRequest(). It is important to note, however, that even though beginRequest does not need |
| * to be explicitly called, {{@link #endRequest(ExternalContext)} does need to be called when the |
| * request has completed or the contract to the configurators will be broken. |
| * |
| * @param ec |
| * the ExternalContext object that should be wrapped. |
| * |
| * @return a decorated ExternalContext object |
| */ |
| @Override |
| public ExternalContext getExternalContext(ExternalContext ec) |
| { |
| RequestStateMap state = RequestStateMap.getInstance(ec); |
| RequestType type = (RequestType) state.get(_REQUEST_TYPE); |
| |
| //Install the URLEncoder plugin system |
| ec = new URLEncoderExternalContext(ec); |
| |
| if (type == null) |
| { |
| beginRequest(ec); |
| type = (RequestType) state.get(_REQUEST_TYPE); |
| } |
| else if (!ExternalContextUtils.getRequestType(ec).equals(type)) |
| { |
| throw new IllegalStateException("The expected request type is not the same as the current request type."); |
| } |
| |
| if (!_isDisabled(ec)) |
| { |
| if (!type.isPortlet() && _isSetRequestBugPresent(ec)) |
| { |
| //This handles bug 493 against the JSF-RI 1.2_03 and earlier. If the bug |
| //is present in the current system, add a wrapper to fix it |
| |
| //TODO sobryan this is somewhat inefficient so should be removed when we |
| //are no longer dependant on JSF1.2_03 or earlier. Still, we only wrap |
| //when we have to so it should be no biggy under normal circumstances. |
| ec = new ClearRequestExternalContext(ec); |
| } |
| |
| // Wrap ExternalContexts |
| for (Configurator config: _services) |
| { |
| ec = config.getExternalContext(ec); |
| } |
| } |
| |
| //After all this request wrapping there is just one more thing we want to handle. IF we are not in a PPR |
| //request AND we are in a processAction, we need to be able to track when a redirect is performed. The |
| //reason for this is that if a redirect is performed during the processAction then we need to remember this |
| //so that we can call the endRequest method when its run. Unlike other request, this WILL call the endRequest |
| //at the end of ProcessAction so the subsequent render will start fresh. In the PPR case, and the case where |
| //we do not have a performAction, we can skip this wrapper. This information will be saved and removed from |
| //the request. |
| if (RequestType.ACTION.equals(type)) |
| { |
| //We have an action, add the wrapper. |
| ec = new RecordRedirectExternalContext(ec); |
| } |
| |
| return ec; |
| } |
| |
| /** |
| * Initializes the global configurator and the configurator services. This method need not be |
| * called directly as it will be called from {@link #beginRequest(ExternalContext)} if needed. It |
| * is also possible to execute this method more then once, although if initialization has already |
| * happened then a call to this method will not do anything. To re-initialize this class, call |
| * {@link #destroy()} first and then call this method. |
| * |
| * @param ec |
| * the externalContext needed to initialize this class |
| * |
| * @see org.apache.myfaces.trinidad.config.Configurator#init(javax.faces.context.ExternalContext) |
| */ |
| @Override |
| public void init(ExternalContext ec) |
| { |
| assert ec != null; |
| |
| if (!_initialized.get()) |
| { |
| try |
| { |
| //For thread saftey. It is possible for two threads to enter this code at the same time. When |
| //the do the second one will wait at the lock until initialization is complete. Then the AtomicBoolean |
| //is checked again for validity. |
| _initLock.lock(); |
| //Check the AtomicBoolean for a change |
| if (!_initialized.get()) |
| { |
| _services = ClassLoaderUtils.getServices(Configurator.class.getName()); |
| |
| // set up the RequestContext Factory as needed. |
| _setupRequestContextFactory(); |
| |
| // Create a new SkinFactory if needed. |
| // SkinFactory is now deprecated. For backward compatibility, SkinFactory internally |
| // calls SkinProvider. So when we init SkinFactory we need to init SkinProvider as well. |
| // SkinProviderRegistry is the implementation of SkinProvider. This in turn needs other |
| // internal SkinProviders such as ExternalSkinProvider, TrinidadSkinProvider to be |
| // available. So we init all of that one by one. |
| if (SkinFactory.getFactory() == null) |
| { |
| SkinFactory.setFactory(new SkinFactoryImpl()); |
| } |
| |
| // init external skin provider before init of SkinProviderRegistry |
| Object externalSkinProvider = ec.getApplicationMap() |
| .get(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY); |
| |
| if (externalSkinProvider == null) |
| ec.getApplicationMap().put(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY, |
| new ExternalSkinProvider()); |
| |
| // init trinidad skin provider before init of SkinProviderRegistry |
| Object trinidadSkinProvider = ec.getApplicationMap() |
| .get(TrinidadSkinProvider.TRINDIAD_SKIN_PROVIDER_KEY); |
| |
| if (trinidadSkinProvider == null) |
| ec.getApplicationMap().put(TrinidadSkinProvider.TRINDIAD_SKIN_PROVIDER_KEY, |
| new TrinidadSkinProvider()); |
| |
| // init skin provider |
| Object provider = ec.getApplicationMap() |
| .get(SkinProvider.SKIN_PROVIDER_INSTANCE_KEY); |
| |
| if (provider == null) |
| ec.getApplicationMap().put(SkinProvider.SKIN_PROVIDER_INSTANCE_KEY, |
| new SkinProviderRegistry()); |
| |
| // init the config property service |
| ConfigPropertyServiceImpl.initialize(ec); |
| |
| for (final Configurator config: _services) |
| { |
| config.init(ec); |
| } |
| |
| // we do not register the skin extensions found in trinidad-skins.xml eagerly. |
| // with SkinProvider SPI we are lazy loading skins as and when required |
| _initialized.set(true); |
| } |
| } |
| finally |
| { |
| //Do cleanup of anything which may have use the thread local manager during |
| //init. |
| _releaseManagedThreadLocals(); |
| _initLock.unlock(); |
| } |
| } |
| else |
| { |
| _LOG.warning("CONFIGURATOR_SERVICES_INITIALIZED"); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| @Deprecated |
| public void reloadSkins(ExternalContext externalContext, SkinFactory skinFactory) |
| { |
| // ask all subordinate configurators to reload their skins |
| // We do not load the base skins and trinidad-skins eagerly. |
| // When any configurator tries to register its skins to the SKinFactory, |
| // it may be calling skinFactory.getSkin(...) to get hold of a base skin. |
| // As SkinFactory is now under SkinProvider SPI, it makes sure that internally all parents are lazy loaded. |
| // thus the caller will get a base Skin which he wants, but we do not load all skins eagerly. |
| for (final Configurator config: _services) |
| { |
| config.reloadSkins(externalContext, skinFactory); |
| } |
| } |
| |
| /** |
| * Hackily called by the ThreadLocalResetter to register itself so that the |
| * GlobalConfiguratorImpl can tell the ThreadLocalResetter to clean up the |
| * ThreadLocals at the appropriate time. |
| */ |
| void __setThreadLocalResetter(ThreadLocalResetter resetter) |
| { |
| if (resetter == null) |
| throw new NullPointerException(); |
| |
| _threadResetter.set(resetter); |
| } |
| |
| /** |
| * Setup request context factory as needed. |
| */ |
| private void _setupRequestContextFactory() |
| { |
| if (RequestContextFactory.getFactory() != null) |
| return; |
| |
| RequestContextFactory requestContextFactory = null; |
| List<RequestContextFactory> factories = ClassLoaderUtils.getServices(RequestContextFactory.class.getName()); |
| ; |
| if (factories.isEmpty()) |
| requestContextFactory = new RequestContextFactoryImpl(); |
| else |
| requestContextFactory = factories.get(0); |
| |
| RequestContextFactory.setFactory(requestContextFactory); |
| } |
| |
| /** |
| * @param ec |
| * @return |
| */ |
| @SuppressWarnings("unchecked") |
| private void _attachRequestContext(ExternalContext ec) |
| { |
| // If someone didn't release the RequestContext on an earlier request, |
| // then it'd still be around, and trying to create a new one |
| // would trigger an exception. We don't want to take down |
| // this thread for all eternity, so clean up after poorly-behaved code. |
| RequestContext context = RequestContext.getCurrentInstance(); |
| if (context != null) |
| { |
| if (_LOG.isWarning()) |
| { |
| _LOG.warning("REQUESTCONTEXT_NOT_PROPERLY_RELEASED"); |
| } |
| _releaseRequestContext(ec); |
| } |
| |
| // See if we've got a cached RequestContext instance; if so, |
| // reattach it |
| Object cachedRequestContext = RequestStateMap.getInstance(ec).get(_REQUEST_CONTEXT); |
| |
| // Catch both the null scenario and the |
| // RequestContext-from-a-different-classloader scenario |
| if (cachedRequestContext instanceof RequestContext) |
| { |
| context = (RequestContext) cachedRequestContext; |
| context.attach(); |
| } |
| else |
| { |
| RequestContextFactory factory = RequestContextFactory.getFactory(); |
| assert factory != null; |
| context = factory.createContext(ec); |
| RequestStateMap.getInstance(ec).put(_REQUEST_CONTEXT, context); |
| } |
| } |
| |
| private void _endRequest(ExternalContext ec, RequestStateMap state) |
| { |
| if (!_isDisabled(ec)) |
| { |
| try |
| { |
| _endConfiguratorServiceRequest(ec, state); |
| } |
| finally |
| { |
| _releaseRequestState(ec); |
| } |
| } |
| } |
| |
| private void _endConfiguratorServiceRequest(ExternalContext ec, RequestStateMap state) |
| { |
| boolean isRedirected = (null != ec.getRequestMap().remove(_REDIRECT_ISSUED)); |
| |
| try |
| { |
| //Only end services at the end of a writable response. This will |
| //generally be RENDER, RESOURCE, and SERVLET. |
| |
| //WE had to add a check to see if a redirect was issued in order to handle a bug where endRequest was not |
| //executed on a redirect. |
| if ((ExternalContextUtils.isResponseWritable(ec) || isRedirected) && |
| !Boolean.TRUE.equals(state.get(_CONFIGURATORS_ABORTED))) |
| { |
| _endConfiguratorServices(ec); |
| } |
| } |
| finally |
| { |
| //If redirect was issued, we do not want to save the state. Let it burn.. :D |
| if (!isRedirected) |
| { |
| state.saveState(ec); |
| } |
| } |
| } |
| |
| private void _releaseRequestState(ExternalContext ec) |
| { |
| try |
| { |
| _releaseThreadLocals(ec); |
| } |
| finally |
| { |
| // ensure that any deferred ComponentReferences are initialized |
| _finishComponentReferenceInitialization(ec); |
| } |
| } |
| |
| private void _releaseThreadLocals(ExternalContext ec) |
| { |
| try |
| { |
| _releaseRequestContext(ec); |
| } |
| finally |
| { |
| _releaseManagedThreadLocals(); |
| } |
| } |
| |
| private void _releaseRequestContext(ExternalContext ec) |
| { |
| RequestContext context = RequestContext.getCurrentInstance(); |
| |
| if (context != null) |
| { |
| context.release(); |
| } |
| } |
| |
| /** |
| * Ensure that any ThreadLocals initialized during this request are cleared |
| */ |
| private void _releaseManagedThreadLocals() |
| { |
| ThreadLocalResetter resetter = _threadResetter.get(); |
| |
| if (resetter != null) |
| { |
| resetter.__removeThreadLocals(); |
| } |
| } |
| |
| /** |
| * Ensure that all DeferredComponentReferences are fully initialized before the |
| * request completes |
| */ |
| private void _finishComponentReferenceInitialization(ExternalContext ec) |
| { |
| Map<String, Object> requestMap = ec.getRequestMap(); |
| |
| Collection<ComponentReference<?>> initializeList = |
| (Collection<ComponentReference<?>>) requestMap.get(_FINISH_INITIALIZATION_LIST_KEY); |
| |
| if ((initializeList != null) && !initializeList.isEmpty()) |
| { |
| RuntimeException initializationException = null; |
| |
| for (ComponentReference<?> reference: initializeList) |
| { |
| try |
| { |
| reference.ensureInitialization(); |
| } |
| catch (RuntimeException rte) |
| { |
| initializationException = rte; |
| } |
| } |
| |
| // we've initialized everything, so we're done |
| initializeList.clear(); |
| |
| // rethrow the exception now that we are all done cleaning up |
| if (initializationException != null) |
| { |
| throw initializationException; |
| } |
| } |
| } |
| |
| private void _endConfiguratorServices(final ExternalContext ec) |
| { |
| // Physical request has now ended |
| // Clear the in-request flag |
| RequestStateMap.getInstance(ec).remove(_IN_REQUEST); |
| if (_services != null) |
| { |
| for (Configurator config: _services) |
| { |
| try |
| { |
| config.endRequest(ec); |
| } |
| catch (Throwable t) |
| { |
| _LOG.severe(t); |
| } |
| } |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private void _startConfiguratorServiceRequest(final ExternalContext ec) |
| { |
| // Physical request has now begun |
| final boolean disabled = isConfiguratorServiceDisabled(ec); |
| |
| // Tell whether the services were disabled when the requests had begun |
| RequestStateMap.getInstance(ec).put(_IN_REQUEST, disabled); |
| |
| // If this hasn't been initialized then please initialize |
| for (Configurator config: _services) |
| { |
| try |
| { |
| config.beginRequest(ec); |
| } |
| catch (Throwable t) |
| { |
| _LOG.severe(t); |
| } |
| } |
| } |
| |
| private boolean _beginWindowManagerRequest(ExternalContext ec) |
| { |
| WindowManager wm = RequestContext.getCurrentInstance().getWindowManager(); |
| boolean cont = true; |
| |
| try |
| { |
| cont = wm.beginRequest(ec); |
| } |
| catch (IOException e) |
| { |
| _LOG.severe(e); |
| } |
| |
| return cont; |
| } |
| |
| static private boolean _isSetRequestBugPresent(ExternalContext ec) |
| { |
| // This first check is here in order to skip synchronization until |
| // absolutely necessary. |
| if (!_sSetRequestBugTested) |
| { |
| synchronized (GlobalConfiguratorImpl.class) |
| { |
| //This second check is here in case a couple of things enter before the |
| //boolean is set. This is only an exception case and will make it so |
| //the initialization code runs only once. |
| if (!_sSetRequestBugTested) |
| { |
| ServletRequest orig = (ServletRequest) ec.getRequest(); |
| // Call getInitParameterMap() up front |
| ec.getInitParameterMap(); |
| |
| ec.setRequest(new TestRequest(orig)); |
| |
| _sHasSetRequestBug = !TestRequest.isTestParamPresent(ec); |
| _sSetRequestBugTested = true; |
| |
| ec.setRequest(orig); |
| } |
| } |
| } |
| |
| return _sHasSetRequestBug; |
| } |
| |
| // This handles an issue with the ExternalContext object prior to |
| // JSF1.2_04. |
| |
| static private class ClearRequestExternalContext |
| extends ExternalContextDecorator |
| { |
| private ExternalContext _ec; |
| private Map<String, Object> _requestCookieMap; |
| private Map<String, String> _requestHeaderMap; |
| private Map<String, String[]> _requestHeaderValuesMap; |
| private Map<String, Object> _requestMap; |
| private Map<String, String> _requestParameterMap; |
| private Map<String, String[]> _requestParameterValuesMap; |
| |
| public ClearRequestExternalContext(ExternalContext ec) |
| { |
| _ec = ec; |
| } |
| |
| @Override |
| protected ExternalContext getExternalContext() |
| { |
| return _ec; |
| } |
| |
| @Override |
| public void setRequest(Object request) |
| { |
| super.setRequest(request); |
| |
| // And clear out any of the cached maps, since we should |
| // go back and look in the map |
| _requestCookieMap = null; |
| _requestHeaderMap = null; |
| _requestHeaderValuesMap = null; |
| _requestMap = null; |
| _requestParameterMap = null; |
| _requestParameterValuesMap = null; |
| } |
| |
| @Override |
| public Map<String, Object> getRequestCookieMap() |
| { |
| _checkRequest(); |
| if (_requestCookieMap == null) |
| { |
| |
| _requestCookieMap = new ServletCookieMap(_getHttpServletRequest()); |
| } |
| return _requestCookieMap; |
| } |
| |
| @Override |
| public Map<String, String> getRequestHeaderMap() |
| { |
| if (_requestHeaderMap == null) |
| { |
| _requestHeaderMap = new ServletRequestHeaderMap(_getHttpServletRequest()); |
| } |
| return _requestHeaderMap; |
| } |
| |
| @Override |
| public Map<String, String[]> getRequestHeaderValuesMap() |
| { |
| if (_requestHeaderValuesMap == null) |
| { |
| _requestHeaderValuesMap = new ServletRequestHeaderValuesMap(_getHttpServletRequest()); |
| } |
| return _requestHeaderValuesMap; |
| } |
| |
| @Override |
| public Map<String, Object> getRequestMap() |
| { |
| _checkRequest(); |
| if (_requestMap == null) |
| { |
| _requestMap = new ServletRequestMap((ServletRequest) getRequest()); |
| } |
| return _requestMap; |
| } |
| |
| @Override |
| public Map<String, String> getRequestParameterMap() |
| { |
| _checkRequest(); |
| if (_requestParameterMap == null) |
| { |
| _requestParameterMap = new ServletRequestParameterMap((ServletRequest) getRequest()); |
| } |
| return _requestParameterMap; |
| } |
| |
| @Override |
| public Map<String, String[]> getRequestParameterValuesMap() |
| { |
| _checkRequest(); |
| if (_requestParameterValuesMap == null) |
| { |
| _requestParameterValuesMap = new ServletRequestParameterValuesMap((ServletRequest) getRequest()); |
| } |
| return _requestParameterValuesMap; |
| } |
| |
| private void _checkRequest() |
| { |
| if (super.getRequest() == null) |
| { |
| throw new UnsupportedOperationException("Request is null on this context."); |
| } |
| } |
| |
| private HttpServletRequest _getHttpServletRequest() |
| { |
| _checkRequest(); |
| if (!(getRequest() instanceof HttpServletRequest)) |
| { |
| throw new IllegalArgumentException("Only HttpServletRequest supported"); |
| } |
| |
| return (HttpServletRequest) getRequest(); |
| } |
| } |
| |
| static private class RecordRedirectExternalContext |
| extends ExternalContextDecorator |
| { |
| public RecordRedirectExternalContext(ExternalContext ec) |
| { |
| assert (ec != null); |
| _ec = ec; |
| } |
| |
| @Override |
| public void redirect(String url) |
| throws IOException |
| { |
| super.redirect(url); |
| |
| //We set a parameter on the request saying that we indeed have a redirect. |
| _ec.getRequestMap().put(_REDIRECT_ISSUED, AppliedClass.APPLIED); |
| } |
| |
| @Override |
| protected ExternalContext getExternalContext() |
| { |
| return _ec; |
| } |
| |
| private ExternalContext _ec; |
| } |
| |
| private static volatile boolean _sSetRequestBugTested = false; |
| private static boolean _sHasSetRequestBug = false; |
| |
| private final ReentrantLock _initLock = new ReentrantLock(); |
| |
| private AtomicBoolean _initialized = new AtomicBoolean(false); |
| private List<Configurator> _services; |
| static private final Map<ClassLoader, GlobalConfiguratorImpl> _CONFIGURATORS = |
| new HashMap<ClassLoader, GlobalConfiguratorImpl>(); |
| static private final String _IN_REQUEST = GlobalConfiguratorImpl.class.getName() + ".IN_REQUEST"; |
| static private final String _REQUEST_CONTEXT = GlobalConfiguratorImpl.class.getName() + ".REQUEST_CONTEXT"; |
| static private final String _REQUEST_TYPE = GlobalConfiguratorImpl.class.getName() + ".REQUEST_TYPE"; |
| |
| static private final String _CONFIGURATORS_ABORTED = |
| GlobalConfiguratorImpl.class.getName() + ".CONFIGURATORS_ABORTED"; |
| |
| //This should be saved on the ManagedRequestScope and needs to implement |
| //@ExcludeFromManagedRequestScope to be totally safe |
| static private final String _REDIRECT_ISSUED = GlobalConfiguratorImpl.class.getName() + ".REDIRECT_ISSUED"; |
| |
| //This will ensure the property is removed on the next request. It should be used |
| //as the value for _REDIRECT_ISSUED. |
| |
| @ExcludeFromManagedRequestScope |
| static private class AppliedClass |
| { |
| static public final AppliedClass APPLIED = new AppliedClass(); |
| } |
| |
| |
| static private class TestRequest |
| extends ServletRequestWrapper |
| { |
| public TestRequest(ServletRequest request) |
| { |
| super(request); |
| } |
| |
| @Override |
| public String getParameter(String string) |
| { |
| if (_TEST_PARAM.equals(string)) |
| { |
| return "passed"; |
| } |
| |
| return super.getParameter(string); |
| } |
| |
| static public final boolean isTestParamPresent(ExternalContext ec) |
| { |
| return RequestStateMap.getInstance(ec).get(_TEST_PARAM) != null; |
| } |
| |
| static private String _TEST_PARAM = TestRequest.class.getName() + ".TEST_PARAM"; |
| } |
| |
| // skanky duplication of key from ComponentReference Class |
| private static final String _FINISH_INITIALIZATION_LIST_KEY = |
| ComponentReference.class.getName() + "#FINISH_INITIALIZATION"; |
| |
| // hacky reference to the ThreadLocalResetter used to clean up request-scoped |
| // ThreadLocals |
| private AtomicReference<ThreadLocalResetter> _threadResetter = new AtomicReference<ThreadLocalResetter>(); |
| |
| static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(GlobalConfiguratorImpl.class); |
| } |