2009-06-16 9 views
2

非開発環境でスタックトレースを抑制するにはfaceslets.developmentをfalseに設定したいが、デバッグではdevでtrueに設定したいと思う。異なる環境でfacelets.developmentをオーバーライドすることはできますか?

デプロイメントプロセスでは、プロダクション環境まで移行される1つのCIビルドが決定されるため、各環境ごとにweb.xmlを書き直す/アプリケーションを再構築する必要はありません。プロパティファイルの設定に基づいて、アプリケーションから値を変更したいと考えています。これは可能ですか?アプリケーションはfacelets.developmentにどのようにアクセスできますか?

答えて

2

私はこれを行うにはいくつかの方法が考えられますが、どれも非常に気持ちの良いものではありません。

  • init parametersをプログラムで制御するためにFacesContextを装飾します。これはほとんど利益のために多くの仕事です。
  • FaceletViewHandlerクラスにパッチを適用して、必要な動作を取得します。 Faceletsライブラリをアップグレードするとメンテナンスオーバーヘッドが増加する可能性があります。プロダクションのアプリを管理する人々を不幸にするかもしれない。
  • パッチアプローチのバリエーションは、dev/testマシンでパッチされたJARを使用してサーバーlibsに配置し、PARENT_FIRSTクラスのロードを使用してアプリケーションのJARにロードすることです(アプリケーションサーバーが)。これの欠点は、クラスローディングポリシーを課すことで、JARを全面的に管理する必要があることです。

私は他のアプローチを好むでしょう。テスト用のマシンでこの設定が必要な場合、おそらくデプロイメントスクリプトがそれらのサーバーのインストール中にアプリケーションを変更する可能性があります。ソースコントロールでtrueに設定する場合、ビルドスクリプトはビルドプロセスの一部としてビルドスクリプトを削除する可能性があります。この方法は、ランタイムコードには影響しません。

1

私は上記のオプション1のバリエーションを実装しました。例えば

  1. (この場合は環境固有のプロパティファイルから供給)適切な値
  2. を返すgetInitParameter及びgetInitParameterNamesメソッドが最初にプロキシFacesContextFactoryImplの非常に小さなサブクラスを書い傍受するServletContextのための動的プロキシを書きました/ servletcontextパラメーターをgetFacesContextに設定し、スーパークラスに委譲します。
  3. FacesContextFactoryImplクラスの名前をfaces-context-factory句に追加しました
  4. 環境固有のプロパティファイルを読み込んでアプリケーションのPropertiesオブジェクト点2における工場はinitParameter値の代替ソースとして使用する点1にプロキシにこれらのプロパティを渡す)

ようプロキシが見える::工場がどのように見える

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が

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

何SystemContext.getInstance()のように見えます。別の日のために運動しているが、それはただのプロパティ値のマップを返しアプリが

2

を使用することになっているようgetConfigPropertiesは()に見える私は、最も簡単な方法は、web.xmlにコンテキストパラメータを置くことであると思う:

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

とし、開発環境でそれを上書きします。これは通常、WARを変更することなく可能です。 Tomcatのには、(<Context> ... </Context>以内)このラインを使用してWARにMETA-INF/context.xmlに含ま:

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

Tomcatが[は、EngineName] $ CATALINA_BASE/confに/に起動時にこのファイルをコピーします/ WARの外部にwebappを設定するために使用できる[hostname]/[context-path-name] .xml。 、Tomcatは新しい/META-INF/context.xmlと新しいWARが展開されている場合でも、それを上書きしません。その後

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

:これは、あなたの環境と管理者のそれぞれにに一度だけ、それを変更する必要が発生します。コンテキストパラメータの名前は、WEB-INF/web.xmlの宣言と一致する必要があります。

詳細については、http://tomcat.apache.org/tomcat-6.0-doc/config/context.html(「はじめに」および「コンテキストパラメータ」セクションを参照)を参照してください。

関連する問題