Можно ли переопределить facelets.development для разных сред? - PullRequest
2 голосов
/ 17 июня 2009

Мы хотели бы установить для facelets.development значение false, чтобы подавить трассировку стека в средах, не предназначенных для разработки, но мы хотели бы установить значение true в dev для отладки.

Наш процесс развертывания требует одной сборки CI, которая переносится из среды в рабочую среду, поэтому мы не можем использовать подход, который требует перестройки приложения / переписывания файла web.xml для каждой среды. Мы хотели бы изменить значение из приложения, основываясь на настройке файла свойств. Это возможно? Как приложение может получить доступ к facelets.development?

Ответы [ 3 ]

3 голосов
/ 09 ноября 2010

Я думаю, что самый простой подход - поместить параметр Context в web.xml:

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

и переопределите его в ваших развертываниях разработки. Обычно это возможно без изменения WAR. В Tomcat включите META-INF / context.xml в WAR-файл с этой строкой (в пределах <Context> ... </Context>):

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

Tomcat скопирует этот файл при запуске в $ CATALINA_BASE / conf / [enginename] / [hostname] / [context-path-name] .xml, который можно использовать для настройки веб-приложения вне WAR. Это произойдет в каждой из ваших сред, и администраторы должны изменить его только один раз:

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

После этого Tomcat не будет перезаписывать его, даже если развернута новая WAR с более новым /META-INF/context.xml. Имена параметров контекста должны соответствовать объявлениям в WEB-INF / web.xml.

Подробнее см. http://tomcat.apache.org/tomcat-6.0-doc/config/context.html (раздел «Введение» и «Параметры контекста»).

2 голосов
/ 17 июня 2009

Я могу придумать несколько способов сделать это, ни один из них не очень приятный.

  • Украсьте FacesContext для программного управления параметрами инициализации . Это большая работа для такой маленькой выгоды.
  • Патч FaceletViewHandler класс, чтобы получить поведение, которое вы хотите. Это может привести к дополнительным расходам на техническое обслуживание, если вы обновите свои библиотеки Facelets. Может расстроить людей, которые управляют приложением на производстве.
  • Разновидность патч-подхода заключается в том, чтобы просто использовать пропатченные JAR-файлы на ваших dev / test машинах и поместить их в библиотеки libs - затем использовать загрузку классов PARENT_FIRST для загрузки их через JAR в приложениях (при условии, что ваш сервер приложений поддерживает все, что ). Недостатком этого является то, что он налагает политики на загрузку классов, и вы должны управлять JAR повсюду.

Я бы предпочел другой подход. Если этот параметр требуется на тестовых компьютерах, возможно, сценарий развертывания может изменить приложение во время установки для этих серверов. Если вы хотите, чтобы в вашем контроле исходного кода было установлено значение true, сценарий сборки может удалить его как часть процесса сборки. Этот подход не повлияет на ваш код времени выполнения.

1 голос
/ 25 января 2010

Я реализовал вариант для варианта 1 выше. например,

  1. написал динамический прокси для ServletContext, который перехватывает методы getInitParameter и getInitParameterNames, возвращающие соответствующие значения (в данном случае полученные из файлов свойств, специфичных для среды)
  2. написал очень маленький подкласс FacesContextFactoryImpl, который передает первый параметр / servletcontext в getFacesContext, а затем делегирует суперклассу.
  3. добавило предложение face-context-factory в мою конфигурацию лиц с именами моего класса 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;
    }
}

Фабрика выглядит так:

<code>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;
 * 
* *

* с настройками в соответствующем файле application.properties, как этот (который * может быть изменено отдельно от веб-приложения) *

* *
 * # Enables special Facelets debug output during development
 * facelets.DEVELOPMENT=true
 * 
* *

* использование: добавить выражение к Face-Config, как это: * *

 *   <factory>
 *   <faces-context-factory>zzzzz.faces.context.FacesContextFactoryImpl</faces-context-factory>
 * </factory>
 * 
*

* * / открытый класс FacesContextFactoryImpl extends com.sun.faces.context.FacesContextFactoryImpl { @SuppressWarnings ( "неиспользуемый") private static final Log log = LogFactory.getLog (FacesContextFactoryImpl.class); public FacesContextFactoryImpl () { супер(); } @Override public FacesContext getFacesContext (Object sc, Запрос объекта, Ответ объекта, Жизненный цикл жизненного цикла) выдает FacesException { if (sc instanceof ServletContext &&! (sc instanceof ServletContextProxy)) { // оборачиваем контекст сервлета прокси для переопределения / дополнения initParameters sc = ServletContextProxy.newInstance ((ServletContext) sc, SystemContext.getInstance () .getConfigProperties (), правда); } вернуть super.getFacesContext (sc, запрос, ответ, жизненный цикл); } }

и face-config выглядит как

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

То, на что похож SystemContext.getInstance (). GetConfigProperties (), является упражнением для другого дня, но оно просто возвращает карту значений свойств, которые приложение должно использовать

...