[ http://issues.apache.org/struts/browse/WW-1414?page=all ]
Christopher Waring updated WW-1414:
-----------------------------------
Attachment: struts-default.xml_diff.txt
> Add support to be able to configure the JSF Application from with in the
> Struts.xml
> -----------------------------------------------------------------------------------
>
> Key: WW-1414
> URL: http://issues.apache.org/struts/browse/WW-1414
> Project: Struts 2
> Issue Type: New Feature
> Components: Configuration, Interceptors
> Affects Versions: 2.0.0, 2.0.1
> Environment: All
> Reporter: Christopher Waring
> Assigned To: Don Brown
> Attachments: FacesSetupInterceptor_diff.txt,
> struts-default.xml_diff.txt
>
>
> Modified org.apache.struts2.jsf.FacesSetupInterceptor to include the ability
> to accept parameters for all of the JSF Application configuration elements.
> This functionality allows multiple elements to be defined using comma
> delimiters. The JSF Application elements that accept classes are constructed
> using constructor delegation. The classes are constructed from the top down
> so that the last class specified will be the one returned and used in the JSF
> Application.set(). See the javaDoc for more information. This change also
> requires an update to the struts-default.xml.
> <b>FacesSetupInterceptor .java:</b>
> /*
> * $Id: TokenInterceptor.java 394468 2006-04-16 12:16:03Z tmjee $
> *
> * Copyright 2006 The Apache Software Foundation.
> *
> * Licensed 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.struts2.jsf;
> import java.lang.reflect.Constructor;
> import java.lang.reflect.InvocationTargetException;
> import java.util.ArrayList;
> import java.util.Iterator;
> import java.util.List;
> import java.util.Locale;
> import javax.faces.FactoryFinder;
> import javax.faces.application.Application;
> import javax.faces.application.ApplicationFactory;
> import javax.faces.application.NavigationHandler;
> import javax.faces.application.StateManager;
> import javax.faces.application.ViewHandler;
> import javax.faces.context.FacesContext;
> import javax.faces.context.FacesContextFactory;
> import javax.faces.el.PropertyResolver;
> import javax.faces.el.VariableResolver;
> import javax.faces.event.ActionListener;
> import javax.faces.lifecycle.Lifecycle;
> import javax.faces.lifecycle.LifecycleFactory;
> import org.apache.struts2.ServletActionContext;
> import org.apache.struts2.StrutsException;
> import org.apache.struts2.util.ClassLoaderUtils;
> import com.opensymphony.xwork2.Action;
> import com.opensymphony.xwork2.ActionInvocation;
> import com.opensymphony.xwork2.config.entities.ActionConfig;
> import com.opensymphony.xwork2.config.entities.ResultConfig;
> import com.opensymphony.xwork2.interceptor.Interceptor;
> /**
> * Initializes the JSF context for this request. <p>
> * </P>
> * The JSF Application can additionaly be configured from the Struts.xml by
> * adding <param> tags to the jsfSetup <interceptor-ref>.<p>
> * </p>
> * <b>Example struts.xml configuration:</b>
> * <pre>
> * <interceptor-ref name="jsfSetup">
> * <param name="actionListener"></param>
> * <param name="defaultRenderKitId"></param>
> * <param name="supportedLocale"></param>
> * <param name="defaultLocale"></param>
> * <param name="messageBundle"></param>
> * <param
> name="navigationHandler">org.apache.struts2.jsf.StrutsNavigationHandler</param>
> * <param name="propertyResolver"></param>
> * <param name="stateManager"></param>
> * <param name="variableResolver">
> * org.apache.myfaces.el.VariableResolverImpl
> * ,org.apache.struts2.jsf.StrutsVariableResolver
> * </param>
> * <param
> name="viewHandler;">org.apache.shale.tiles.TilesViewHandler</param>
> * </interceptor-ref>
> * </pre><p>
> * </p>
> * <b>Note: None of the parameters are required but all are shown in the
> example
> * for completeness.</b>
> */
> public class FacesSetupInterceptor extends FacesSupport implements
> Interceptor {
> private static final long serialVersionUID = -621512342655103941L;
> private String lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
> private FacesContextFactory facesContextFactory;
> private Lifecycle lifecycle;
>
> // jsf Application configuration
> private List <String> actionListener;
> private String defaultRenderKitId;
> private List <String> supportedLocale;
> private String defaultLocale;
> private String messageBundle;
> private List <String> navigationHandler;
> private List <String> propertyResolver;
> private List <String> stateManager;
> private List <String> variableResolver;
> private List <String> viewHandler;
> /**
> * Sets the lifecycle id
> *
> * @param id The id
> */
> public void setLifecycleId(String id) {
> this.lifecycleId = id;
> }
> /**
> * Initializes the lifecycle and factories
> */
> public void init() {
> try {
> facesContextFactory = (FacesContextFactory)
> FactoryFinder
>
> .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
> } catch (Exception ex) {
> log.debug("Unable to initialize faces", ex);
> }
>
> if (facesContextFactory == null) {
> log.info("Unable to initialize jsf interceptors
> probably due missing JSF framework initialization");
> return;
> }
> // Javadoc says: Lifecycle instance is shared across multiple
> // simultaneous requests, it must be implemented in a
> thread-safe
> // manner.
> // So we can acquire it here once:
> LifecycleFactory lifecycleFactory = (LifecycleFactory)
> FactoryFinder
> .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
> lifecycle = lifecycleFactory.getLifecycle(lifecycleId);
> Application application = ((ApplicationFactory) FactoryFinder
> .getFactory(FactoryFinder.APPLICATION_FACTORY))
> .getApplication();
>
> if (actionListener != null) {
> Iterator i = actionListener.iterator();
> application.setActionListener((ActionListener)
> getApplicationObject(ActionListener.class,
> i, application.getActionListener()));
> }
> if (defaultRenderKitId != null && defaultRenderKitId.length() >
> 0) {
> application.setDefaultRenderKitId(defaultRenderKitId);
> }
>
> if (messageBundle != null && messageBundle.length() > 0) {
> application.setMessageBundle(messageBundle);
> }
> if (supportedLocale != null) {
> List<Locale> locales = new ArrayList<Locale>();
> for (Iterator i = supportedLocale.iterator(); i.hasNext();) {
> locales.add(toLocale((String) i.next()));
> }
> application.setSupportedLocales(locales);
> }
> if (defaultLocale != null && defaultLocale.length() > 0) {
> application.setDefaultLocale(toLocale(defaultLocale));
> }
> if (navigationHandler != null) {
> Iterator i = navigationHandler.iterator();
> application.setNavigationHandler((NavigationHandler)
> getApplicationObject(NavigationHandler.class,
> i, application.getNavigationHandler()));
> }
>
> if (propertyResolver != null) {
> Iterator i = propertyResolver.iterator();
> application.setPropertyResolver((PropertyResolver)
> getApplicationObject(PropertyResolver.class,
> i, application.getPropertyResolver()));
> }
>
> if (stateManager != null) {
> Iterator i = stateManager.iterator();
> application.setStateManager((StateManager)
> getApplicationObject(StateManager.class,
> i, application.getStateManager()));
> }
>
> if (variableResolver != null) {
> Iterator i = variableResolver.iterator();
> application.setVariableResolver((VariableResolver)
> getApplicationObject(VariableResolver.class,
> i, application.getVariableResolver()));
> }
>
> if (viewHandler != null) {
> Iterator i = viewHandler.iterator();
> application.setViewHandler((ViewHandler)
> getApplicationObject(ViewHandler.class,
> i, application.getViewHandler()));
> }
> }
> /**
> * Creates the faces context for other phases.
> *
> * @param invocation
> * The action invocation
> */
> public String intercept(ActionInvocation invocation) throws Exception {
> if (facesContextFactory != null && isFacesAction(invocation)) {
>
> invocation.getInvocationContext().put(
> FacesInterceptor.FACES_ENABLED, Boolean.TRUE);
>
> FacesContext facesContext =
> facesContextFactory.getFacesContext(
>
> ServletActionContext.getServletContext(), ServletActionContext
> .getRequest(),
> ServletActionContext.getResponse(),
> lifecycle);
>
> setLifecycle(lifecycle);
>
> try {
> return invocation.invoke();
> } finally {
> facesContext.release();
> }
> } else {
> return invocation.invoke();
> }
> }
>
> /**
> * Cleans up the lifecycle and factories
> */
> public void destroy() {
> facesContextFactory = null;
> lifecycle = null;
> }
>
> /**
> * Determines if this action mapping will be have a JSF view
> *
> * @param inv The action invocation
> * @return True if the JSF interceptors should fire
> */
> protected boolean isFacesAction(ActionInvocation inv) {
> ActionConfig config = inv.getProxy().getConfig();
> if (config != null) {
> ResultConfig resultConfig =
> config.getResults().get(Action.SUCCESS);
> Class resClass = null;
> try {
> resClass = Class.forName(resultConfig.getClassName());
> } catch (ClassNotFoundException ex) {
> log.warn("Can't find result class, ignoring as a faces
> request", ex);
> }
> if (resClass != null) {
> if (resClass.isAssignableFrom(FacesResult.class)) {
> return true;
> }
> }
> }
> return false;
> }
>
> /**
> * Constructs an object from a list of class names. This method
> supports creating
> * the objects using constructor delegation, if the requested class
> supports it. Classes will
> * be imbedded from top to bottom in the list with the last class
> listed being the one that will
> * be returned.
> * @param interfaceClass The Class type that is expected to be returned
> * @param classNamesIterator An Iterator for a list of Strings that
> represent the class names
> * @param defaultObject The current Object that the jsf Application has
> set
> * @return
> */
> private Object getApplicationObject(Class interfaceClass, Iterator
> classNamesIterator, Object defaultObject) {
> Object current = defaultObject;
> while (classNamesIterator.hasNext()) {
> String implClassName = (String) classNamesIterator.next();
> Class implClass = null;
>
> try {
> implClass = ClassLoaderUtils.loadClass(implClassName,
> this.getClass());
> } catch (ClassNotFoundException e1) {
> throw new IllegalArgumentException("Class " +
> implClassName + " was not found.");
> }
>
> // check, if class is of expected interface type
> if (!interfaceClass.isAssignableFrom(implClass)) {
> throw new IllegalArgumentException("Class " + implClassName +
> " is no " + interfaceClass.getName());
> }
> if (current == null) {
> // nothing to decorate
> try {
> current = implClass.newInstance();
> } catch (InstantiationException e) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> } catch (IllegalAccessException e) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> }
> } else {
> // let's check if class supports the decorator pattern
> try {
> Constructor delegationConstructor =
> implClass.getConstructor(new Class[]{interfaceClass});
> // impl class supports decorator pattern,
> try {
> // create new decorator wrapping current
> current = delegationConstructor.newInstance(new
> Object[]{current});
> } catch (InstantiationException e) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> } catch (IllegalAccessException e) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> } catch (InvocationTargetException e) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> }
> } catch (NoSuchMethodException e) {
> // no decorator pattern support
> try {
> current = implClass.newInstance();
> } catch (InstantiationException e1) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> } catch (IllegalAccessException e1) {
> log.error(e.getMessage(), e);
> throw new StrutsException(e);
> }
> }
> }
> }
> return current;
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param actionListener A comma delimited string of class names
> */
> public void setActionListener(String actionListener) {
> if (this.actionListener == null) {
> this.actionListener = new ArrayList<String>();
> }
> String clean = actionListener.replaceAll("[ \t\r\n]", "");
> String[] actionListenerNames = clean.split(",");
>
> for (int i = 0;i < actionListenerNames.length; i++) {
> this.actionListener.add(actionListenerNames[i]);
> }
> }
> /**
> * A <code>String</code> to be used as the defaultRenderKitId for the
> jsf application.
> * The incoming <code>String</code> will be cleaned of whitespace
> characters.
> * @param defaultRenderKitId The defaultRenderKitId
> */
> public void setDefaultRenderKitId(String defaultRenderKitId) {
> String clean = defaultRenderKitId.replaceAll("[ \t\r\n]", "");
> this.defaultRenderKitId = clean;
> }
>
> /**
> * Takes a comma delimited string of local names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param supportedLocale A comma delimited string of local names
> */
> public void setSupportedLocale(String supportedLocale) {
> if (this.supportedLocale == null) {
> this.supportedLocale = new ArrayList<String>();
> }
> String clean = supportedLocale.replaceAll("[ \t\r\n]", "");
> String[] supportedLocaleNames = clean.split(",");
>
> for (int i = 0;i < supportedLocaleNames.length; i++) {
> this.supportedLocale.add(supportedLocaleNames[i]);
> }
> }
> /**
> * Stores a String representation of the defaultLocale. The incoming
> <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param defaultLocale The default local
> */
> public void setDefaultLocale(String defaultLocale) {
> String clean = defaultLocale.replaceAll("[ \t\r\n]", "");
> this.defaultLocale = clean;
> }
> /**
> * Stores the messageBundle to be used to configure the jsf Application.
> * @param messageBundle The messageBundle
> */
> public void setMessageBundle(String messageBundle) {
> String clean = messageBundle.replaceAll("[ \t\r\n]", "");
> this.messageBundle = clean;
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param navigationHandlerName A comma delimited string of class names
> */
> public void setNavigationHandler(String navigationHandlerName) {
> if (navigationHandler == null) {
> navigationHandler = new ArrayList<String>();
> }
> String clean = navigationHandlerName.replaceAll("[ \t\r\n]",
> "");
> String[] navigationHandlerNames = clean.split(",");
>
> for (int i = 0;i < navigationHandlerNames.length; i++) {
> navigationHandler.add(navigationHandlerNames[i]);
> }
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param propertyResolverName A comma delimited string of class names
> */
> public void setPropertyResolver(String propertyResolverName) {
> if (propertyResolver == null) {
> propertyResolver = new ArrayList<String>();
> }
> String clean = propertyResolverName.replaceAll("[ \t\r\n]", "");
> String[] propertyResolverNames = clean.split(",");
>
> for (int i = 0;i < propertyResolverNames.length; i++) {
> propertyResolver.add(propertyResolverNames[i]);
> }
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param stateManagerName A comma delimited string of class names
> */
> public void setStateManager(String stateManagerName) {
> if (stateManager == null) {
> stateManager = new ArrayList<String>();
> }
> String clean = stateManagerName.replaceAll("[ \t\r\n]", "");
> String[] stateManagerNames = clean.split(",");
>
> for (int i = 0;i < stateManagerNames.length; i++) {
> stateManager.add(stateManagerNames[i]);
> }
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param variableResolverName A comma delimited string of class names
> */
> public void setVariableResolver(String variableResolverName) {
> if (variableResolver == null) {
> variableResolver = new ArrayList<String>();
> }
> String clean = variableResolverName.replaceAll("[ \t\r\n]", "");
> String[] variableResolverNames = clean.split(",");
>
> for (int i = 0;i < variableResolverNames.length; i++) {
> variableResolver.add(variableResolverNames[i]);
> }
> }
> /**
> * Takes a comma delimited string of class names and stores the names
> * in an <code>ArrayList</code>. The incoming <code>String</code> will
> * be cleaned of any whitespace characters before the class names are
> stored.
> * @param viewHandlerName A comma delimited string of class names
> */
> public void setViewHandler(String viewHandlerName) {
> if (viewHandler == null) {
> viewHandler = new ArrayList<String>();
> }
> String[] viewHandlerNames= viewHandlerName.split(",^[
> \t\r\n]+|[ \t\r\n]+$");
>
> for (int i = 0;i < viewHandlerNames.length; i++) {
> viewHandler.add(viewHandlerNames[i]);
> }
> }
>
> /**
> * Converts a locale string to <code>Locale</code> class. Accepts both
> * '_' and '-' as separators for locale components.
> *
> * @param localeString string representation of a locale
> * @return Locale instance, compatible with the string representation
> */
> private Locale toLocale(String localeString) {
> if ((localeString == null) || (localeString.length() == 0)) {
> Locale locale = Locale.getDefault();
> if(log.isWarnEnabled())
> log.warn("Locale name in faces-config.xml null or empty,
> setting locale to default locale : "+locale.toString());
> return locale;
> }
> int separatorCountry = localeString.indexOf('_');
> char separator;
> if (separatorCountry >= 0) {
> separator = '_';
> } else {
> separatorCountry = localeString.indexOf('-');
> separator = '-';
> }
> String language, country, variant;
> if (separatorCountry < 0) {
> language = localeString;
> country = variant = "";
> } else {
> language = localeString.substring(0, separatorCountry);
> int separatorVariant = localeString.indexOf(separator,
> separatorCountry + 1);
> if (separatorVariant < 0) {
> country = localeString.substring(separatorCountry + 1);
> variant = "";
> } else {
> country = localeString.substring(separatorCountry + 1,
> separatorVariant);
> variant = localeString.substring(separatorVariant + 1);
> }
> }
> return new Locale(language, country, variant);
> }
> }
> <b>struts-default.xml (SNIPPET)</b>
> <!-- Sample JSF stack, can be combined with other stacks easily -->
> <interceptor-stack name="jsfStack">
> <interceptor-ref name="jsfSetup">
> <param
> name="variableResolver">org.apache.struts2.jsf.StrutsVariableResolver</param>
> <param
> name="navigationHandler">org.apache.struts2.jsf.StrutsNavigationHandler</param>
> </interceptor-ref>
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://issues.apache.org/struts/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira