代码之家  ›  专栏  ›  技术社区  ›  Nicholas Trandem

是否可以覆盖不同环境下的facelets.development?

  •  2
  • Nicholas Trandem  · 技术社区  · 17 年前

    我们希望将facelets.development设置为false以抑制非开发环境中的堆栈跟踪,但我们希望在dev中将其设置为true以进行调试。

    我们的部署过程要求在生产环境中迁移一个CI构建,因此我们不能使用需要为每个环境重新构建app/rewrite web.xml的方法。我们希望根据属性文件设置更改应用程序中的值。这有可能吗?应用程序如何访问facelets.development?

    3 回复  |  直到 16 年前
        1
  •  2
  •   McDowell rahul gupta    17 年前

    我可以想出一些方法来做到这一点,它们都不是很愉快的。

    • 装饰 FacesContext 控制 init parameters 以编程方式。这是很多工作,却没有什么收获。
    • 修补 FaceletViewHandler 来获得你想要的行为。如果升级facelets libs,这可能会增加维护开销。可能会让那些在生产中管理应用程序的人不高兴。
    • 补丁方法的一个变化是,只需在开发/测试机器中使用补丁jar,并将它们放在服务器libs中,然后使用父级的“第一类加载”将它们加载到应用程序中的jar上(假设您的应用服务器支持所有这些)。这样做的缺点是它强加了类装载策略,并且您必须在整个地方管理jar。

    我赞成其他的办法。如果测试机器上需要此设置,那么部署脚本可能会在安装这些服务器的过程中修改应用程序。如果希望在源代码管理中将其设置为true,则生成脚本可以将其作为生成过程的一部分删除。这种方法不会对运行时代码产生影响。

        2
  •  3
  •   oldo    16 年前

    我认为最简单的方法是将上下文参数放在web.xml中:

    <context-param>
      <param-name>facelets.DEVELOPMENT</param-name>
      <param-value>false</param-value>
    </context-param>
    

    并在开发部署中覆盖它。这通常在不改变战争的情况下是可能的。在Tomcat中,将META-INF/context.xml包含在您与此行的战争中(在 <Context> … </Context> ):

    <Parameter name="facelets.DEVELOPMENT" value="true" override="false" />
    

    Tomcat将在启动时将此文件复制到$catalina_base/conf/[enginename]/[hostname]/[context path name].xml,该xml可用于在 战争。这将在您的每个环境中发生,管理员只需将其更改一次即可:

    <Parameter name="facelets.DEVELOPMENT" value="false" override="false" />
    

    之后,即使部署了新的/META-INF/context.xml,Tomcat也不会覆盖它。上下文参数的名称必须与WEB-INF/WEB.XML中的声明匹配。

    见 http://tomcat.apache.org/tomcat-6.0-doc/config/context.html 有关详细信息(“简介”和“上下文参数”部分)。

        3
  •  1
  •   laurie    16 年前

    我在上面的选项1上实现了一个变体。如

    1. 为servletContext编写了一个动态代理,该代理截取getinitparameter和getinitparameternames方法,这些方法返回适当的值(在本例中,源于特定于环境的属性文件)。
    2. 编写了FacesContextFactoryImpl的一个非常小的子类,它将第一个/servletContext参数代理到getFacesContext,然后代理到超类。
    3. 将faces上下文factory子句添加到我的faces配置中,命名我的facesContextFactoryImpl类
    4. 我已经有了一种机制来加载特定于环境的属性文件,并将它们作为属性对象提供给应用程序(点2中的工厂将这些属性传递给点1中的代理,以用作initparameter值的备用源)

    代理程序如下:

    package zzzzz.framework.context;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Enumeration;
    import java.util.Hashtable;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    
    import org.apache.commons.collections.IteratorUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * A proxy for ServletContext that intercepts accesses to the initParameters and
     * returns values from the specified params instead. Generally useful if we have
     * a set of properties (eg SystemContext.getInstance().getConfigProperties()) that
     * we want to use in preference to the webapp initProperties.
     * 
     * 
     */
    public class ServletContextProxy
            implements InvocationHandler {
        @SuppressWarnings("unused")
        private static final Log log = LogFactory.getLog(ServletContextProxy.class);
    
        @SuppressWarnings("unchecked")
        public static ServletContext newInstance(ServletContext subject,
                Map params) {
            return newInstance(subject,
                    params,
                    true);
        }
    
        @SuppressWarnings("unchecked")
        public static ServletContext newInstance(ServletContext subject,
                Map params,
                boolean overrideInitValues) {
            return (ServletContext) Proxy.newProxyInstance(subject.getClass()
                    .getClassLoader(),
                    subject.getClass()
                            .getInterfaces(),
                    new ServletContextProxy(subject,
                            params,
                            overrideInitValues));
        }
    
        /**
         * A convenience method to help extracting the initParameters from a
         * ServletContext because it doesn't expose it's underlying Map
         * 
         * @param config
         * @return
         */
        @SuppressWarnings("unchecked")
        protected static Map copyInitParameters(Map parms,
                ServletContext config) {
            Enumeration names = config.getInitParameterNames();
            // copy all the existing initParameters
            while (names.hasMoreElements()) {
                String name = (String) names.nextElement();
                parms.put(name,
                        config.getInitParameter(name));
            }
            return parms;
        }
    
        private boolean overrideInitValues = true;
    
        @SuppressWarnings("unchecked")
        private Map params;
        private ServletContext subject;
    
        @SuppressWarnings("unchecked")
        public ServletContextProxy(ServletContext subject,
                Map params,
                boolean overrideInitValues) {
            this.subject = subject;
            this.overrideInitValues = overrideInitValues;
            this.params = new Hashtable();
            if (this.overrideInitValues) { // default behaviour... supplied parameters win
                // start with initParameters
                copyInitParameters(this.params,
                        subject);
                // override and supplement with supplied params
                if (params != null) {
                    this.params.putAll(params);
                }
            } else {
                // start with supplied params
                if (params != null) {
                    this.params.putAll(params);
                }
                // override and supplement with initParameters
                copyInitParameters(this.params,
                        subject);
    
            }
        }
    
        public Object invoke(Object proxy,
                Method m,
                Object[] args) throws Throwable {
            Object result;
            try {
                if ("getInitParameter".equals(m.getName())) {
                    result = this.params.get(args[0]);
                } else if ("getInitParameterNames".equals(m.getName())) {
                    result = IteratorUtils.asEnumeration(this.params.keySet()
                            .iterator());
                } else {// else let it go through to the keeper
                    result = m.invoke(this.subject,
                            args);
                }
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            } catch (Exception e) {
                throw new RuntimeException("unexpected invocation exception: "
                        + e.getMessage());
            }
            return result;
        }
    }
    

    工厂看起来像:

    package zzz.faces.context;
    
    import javax.faces.FacesException;
    import javax.faces.context.FacesContext;
    import javax.faces.lifecycle.Lifecycle;
    import javax.servlet.ServletContext;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import zzzzz.framework.context.ServletContextProxy;
    import zzzzz.context.SystemContext;
    
    /**
     * A FacesContextFactory implementation that supplements/overrided the
     * servletContext initParemeters with properties form
     * SystemContext.configProperties
     * <p>
     * The point of this is that it allows us to substitute configuration in the
     * web.xml like this (which requires rewriting web.xml to change)
     * </p>
     * 
     * <pre>
     *   &lt;!-- Enables special Facelets debug output during development --&gt;
     * &lt;context-param&gt;
     *   &lt;param-name&gt;facelets.DEVELOPMENT&lt;/param-name&gt;
     *   &lt;param-value&gt;true&lt;/param-value&gt;
     * &lt;/context-param&gt;
     * </pre>
     * 
     * <p>
     * with settings in the relevent application.properties file like this (which
     * can be changed separately to the webapp)
     * </p>
     * 
     * <pre>
     * # Enables special Facelets debug output during development
     * facelets.DEVELOPMENT=true
     * </pre>
     * 
     * <p>
     * usage: add a clause to faces-config like this:
     * 
     * <pre>
     *   <factory>
     *   <faces-context-factory>zzzzz.faces.context.FacesContextFactoryImpl</faces-context-factory>
     * </factory>
     * </pre>
     * <p>
     * 
     */
    public class FacesContextFactoryImpl extends com.sun.faces.context.FacesContextFactoryImpl {
        @SuppressWarnings("unused")
        private static final Log log = LogFactory.getLog(FacesContextFactoryImpl.class);
    
        public FacesContextFactoryImpl() {
            super();
        }
    
        @Override
        public FacesContext getFacesContext(Object sc,
                Object request,
                Object response,
                Lifecycle lifecycle) throws FacesException {
    
            if (sc instanceof ServletContext
                    && !(sc instanceof ServletContextProxy)) {
                // wrap the servlet context with a proxy to override/supplement initParameters
                sc = ServletContextProxy.newInstance((ServletContext) sc,
                        SystemContext.getInstance()
                                .getConfigProperties(),
                        true);
            }
            return super.getFacesContext(sc,
                    request,
                    response,
                    lifecycle);
        }
    }
    

    人脸配置看起来像

        <faces-config>
      blah waffle....
          <factory>
            <faces-context-factory>zzzz.faces.context.FacesContextFactoryImpl</faces-context-factory>
          </factory>
        </faces-config>
    

    SystemContext.GetInstance().getConfigProperties()看起来像是另一天的练习,但它只返回应用程序应该使用的属性值的映射。

    推荐文章