You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by so...@apache.org on 2014/04/16 20:38:28 UTC

svn commit: r1588021 - in /myfaces/trinidad/trunk: ./ trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/

Author: sobryan
Date: Wed Apr 16 18:38:28 2014
New Revision: 1588021

URL: http://svn.apache.org/r1588021
Log:
TRINIDAD-2439: Plugable configuration parameter provider

*Thanks for the patch Dave

Added:
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java   (with props)
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java   (with props)
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java   (with props)
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java   (with props)
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java   (with props)
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java   (with props)
Modified:
    myfaces/trinidad/trunk/pom.xml
    myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java

Modified: myfaces/trinidad/trunk/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/pom.xml?rev=1588021&r1=1588020&r2=1588021&view=diff
==============================================================================
--- myfaces/trinidad/trunk/pom.xml (original)
+++ myfaces/trinidad/trunk/pom.xml Wed Apr 16 18:38:28 2014
@@ -409,6 +409,7 @@ Create A Branch (http://maven.apache.org
 
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.17</version>
           <inherited>true</inherited>
           <configuration>
             <parallel>true</parallel>

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,112 @@
+/*
+ * 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.trinidad.config;
+
+import java.beans.PropertyChangeListener;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ *  This class allows access to configuration properties supplied by a plugable
+ *  property value provider.  Using a plugable property value provider separates
+ *  access to property values from where the values are stored, allowing different
+ *  property storage and configuration schemes to be used without impacting code
+ *  that uses the property values.
+ *  <p>
+ *  See {@link PropertyValueProvider PropertyValueProvider} for information
+ *  on configuring a property value provider.
+ *  <p>
+ *  Implementation os this class are required to be thread safe allowing multiple
+ *  threads to invoke methods on an instance concurrently.
+ */
+public abstract class ConfigPropertyService
+{
+  /**
+   * Obtain a reference to the service.
+   *
+   * @param externalContext  container context object.
+   * @return  service object for obtaining property values.
+   */
+  public static ConfigPropertyService getInstance(ExternalContext externalContext)
+  {
+    ConfigPropertyService service =
+      (ConfigPropertyService) externalContext.getApplicationMap().get(CONFIG_PROPERTY_SERVICE_KEY);
+    if (service == null)
+    {
+      throw new IllegalStateException(_LOG.getMessage("CONFIG_PROPERTY_SERVICE_NOT_INITIALIZED"));
+    }
+    return service;
+  }
+
+  /**
+   * @param externalContext  container context object.
+   * @param name  name of the requested property.
+   * @return  the value of the property or <code>null</code> if the property was not found.
+   * @throws NullPointerException is the specified name is null.
+   */
+  public abstract String getProperty(ExternalContext externalContext, String name);
+
+  /**
+   * Register a listener to be informed if/when a property value is changed.
+   * <p>
+   * The {@link ConfigPropertyService ConfigPropertyService} will be specified as the
+   * 'source' attribute of any change events the listener receives.
+   *
+   * @param listener  the listener to be notified of property value changes.
+   */
+  public abstract void addPropertyChangeListener(PropertyChangeListener listener);
+
+  /**
+   * Unregister a property change listener.
+   * @param listener  the listener to unregister.
+   */
+  public abstract void removePropertyChangeListener(PropertyChangeListener listener);
+
+  /**
+   * Get the test value provider.  If one is not currently in the collection of value providers a
+   * new instance will be created and added to the collection.  An implementation of this class
+   * should not allow more than one instance of {@ TestPropertyValueProvider TestPropertyValueProvider}
+   * in its collection of value providers.
+   *
+   * @return  a test value provider.
+   */
+  protected abstract TestPropertyValueProvider getTestProvider();
+
+  /**
+   * Notify value change listeners of a config property value change.
+   * @param name  the name of the property who's value changed.
+   * @param oldValue  the previous value of the property.
+   * @param newValue  the new value of the property.
+   */
+  //
+  //  Note: this method is not public because it's expected to only be invoked by
+  //        PropertyValueProvider which is in the same package.
+  //
+  protected abstract void notifyValueChange(ExternalContext externalContext, String name, String oldValue);
+
+  /**
+   * Key used to store the application's ConfigPropertyService instance in the applicationScope map.
+   */
+  protected static final String CONFIG_PROPERTY_SERVICE_KEY =
+    "org.apache.myfaces.trinidad.config.CONFIG_PROPERTY_SERVICE_INSTANCE";
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ConfigPropertyService.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ConfigPropertyService.java
------------------------------------------------------------------------------
    svn:executable = *

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,76 @@
+/*
+ * 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.trinidad.config;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ * Abstract base class for configurable property value providers.
+ * <p>
+ * A PropertyValueProvider can be registered by placing
+ * <code>/META-INF/services/org.apache.myfaces.trinidad.config.PropertyValueProvider</code>
+ * on the classpath containing the fully qualified name of the implementation class.
+ * <p>
+ * Note: at this time the framework only supports one PropertyValueProvider being registered
+ * to avoid provider ordering issues.
+ *  <p>
+ *  Implementation os this class are required to be thread safe allowing multiple
+ *  threads to invoke methods on an instance concurrently.
+ */
+public abstract class PropertyValueProvider
+{
+  /**
+   * Constructor.
+   */
+  protected PropertyValueProvider()
+  {
+  }
+
+  /**
+   * Fetch a property value.  There is no concurrency control provided by the property service so
+   * all implementations of this method are required to be thread safe or to perform their own
+   * concurrency control.
+   * @param externalContext  container context object.
+   * @param name  name of the requested property.
+   * @return  the value of the property or <code>null</code> if the property was not found.
+   * @throws NullPointerException if the supplied property name is null.
+   */
+  public abstract String getValue(ExternalContext externalContext, String name);
+
+  /**
+   * Implementations of this class are required to call this method when a property value is changed.
+   * @param externalContext  container context object.
+   * @param name  the name of the property who's value changed.
+   * @param oldValue  the previous value of the property.
+   * @param newValue  the new value of the property.
+   */
+  protected final void notifyValueChanged(ExternalContext externalContext, String name, String oldValue)
+  {
+    ConfigPropertyService service = ConfigPropertyService.getInstance(externalContext);
+    if (service == null)
+    {
+      throw new IllegalStateException(_LOG.getMessage("CONFIG_PROPERTY_SERVICE_NOT_INITIALIZED"));
+    }
+    service.notifyValueChange(externalContext, name, oldValue);
+  }
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(PropertyValueProvider.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/PropertyValueProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,142 @@
+/*
+ * 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.trinidad.config;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ *  A {@link PropertyValueProvider PropertyValueProvider} that allows runtime modification
+ *  of property values to support unit testing code.  By using this class a unit test can
+ *  exercise a piece of code with a number of different property values without needing to
+ *  change property values in their underlaying source.
+ *  <p>
+ *  This class maintains an in-memory collection of property values supplied by calling the
+ *  {@link TestPropertyValueProvider#setProperty setProperty} method.  When a value is requested
+ *  by the {@link ConfigPropertyService ConfigPropertyService} the in-memory collection of
+ *  values are consulted first.  If a value has been supplied that will be returned, otherwise
+ *  the property value will be fetched from the configured property value provider.
+ *  <p>
+ *  When this class is used it will coordinate with the {@link ConfigPropertyService ConfigPropertyService}
+ *  to ensure values are obained from this class.
+ */
+public final class TestPropertyValueProvider
+  extends PropertyValueProvider
+{
+  public TestPropertyValueProvider()
+  {
+  }
+
+  /**
+   * Obtain a reference to the test value provider.  Calling this method will also result
+   * in the test property value provider being installed with the
+   * {@link ConfigPropertyService ConfigPropertyService}.
+   *
+   * @return  a test value provider.
+   */
+  public static TestPropertyValueProvider getInstance(ExternalContext externalContext)
+  {
+    ConfigPropertyService service = ConfigPropertyService.getInstance(externalContext);
+    if (service == null)
+    {
+      throw new IllegalStateException(_LOG.getMessage("CONFIG_PROPERTY_SERVICE_NOT_INITIALIZED"));
+    }
+    return service.getTestProvider();
+  }
+
+  /**
+   *  Used by the {@link ConfigPropertyService ConfigPropertyService} to obtain a property value.
+   *  If a value has been specified by calling the {@link TestPropertyValueProvider#setProperty setProperty}
+   *  method that value will be returned, otherwise the request will be delegated to the configured
+   *  property value provider.
+   *
+   *  @param extCtx {@inheritDoc}
+   *  @param name {@inheritDoc}
+   *  @return {@inheritDoc}
+   */
+  @Override
+  public String getValue(ExternalContext extCtx, String name)
+  {
+    String value;
+    if (name != null)
+    {
+      value = _testValues.get(name);
+    }
+    else
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+    return value;
+  }
+
+  /**
+   *  Set the value of a property.  Calling this method only updates the in-memory value used for
+   *  test purposes.  The value is not propagated to any underlying storage.
+   *  <p>
+   *  Any PropertyChangeListener reqiested with the {@link ConfigPropertyService ConfigPropertyService}
+   *  will be notified of the value change when this method is called.
+   *
+   *  @param externalContext  container context object.
+   *  @param name name of the property.
+   *  @param value value of the property.
+   *  @throws NullPointerException if the property name is null.
+   */
+  public void setProperty(ExternalContext externalContext, String name, String value)
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+    String oldValue = ConfigPropertyService.getInstance(externalContext).getProperty(externalContext, name);
+    _testValues.put(name, value);
+    notifyValueChanged(externalContext, name, oldValue);
+  }
+
+  /**
+   *  Remove a property value from the test value provider.
+   *  @param name  name of the property.
+   *  @throws NullPointerException if the property name is null.
+   */
+  public void removeProperty(ExternalContext externalContext, String name)
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+    String oldValue = ConfigPropertyService.getInstance(externalContext).getProperty(externalContext, name);
+    _testValues.remove(name);
+    notifyValueChanged(externalContext, name, oldValue);
+  }
+
+  /**
+   *  Removes all in-memory property values specified by calling
+   *  {@link TestPropertyValueProvider#setProperty setProperty}, returning them to their original values.
+   */
+  public void resetValues()
+  {
+    _testValues.clear();
+  }
+
+  private final ConcurrentHashMap<String, String> _testValues = new ConcurrentHashMap<String, String>();
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(TestPropertyValueProvider.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/TestPropertyValueProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts?rev=1588021&r1=1588020&r2=1588021&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts Wed Apr 16 18:38:28 2014
@@ -566,5 +566,8 @@
 <resource key="INVALID_RESOURCE_SIZE">Invalid resource size detected.  The resource at '{0}' appears to be {1} bytes, but URLConnection.getContentLength() for this resource reports {2}.</resource>
 
 <resource key="RESOURCE_SIZE_CHANGED">Resource size changed.  A new content length of {0} bytes has been detected for the resource {1}. Removing resource from cache.</resource>
+<resource key="MULTIPLE_CONFIG_PROPERTY_PROVIDERS_FOUND">Multiple PropertyValueProviders configured on the classpath, only one is allowed.</resource>
+<resource key="NULL_CONFIG_PROPERTY_NAME">Config property name can not be null.</resource>
+<resource key="CONFIG_PROPERTY_SERVICE_NOT_INITIALIZED">The config property service has not been initialized.</resource>
 
 </resources>

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,170 @@
+/*
+ * 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.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.config.ConfigPropertyService;
+import org.apache.myfaces.trinidad.config.PropertyValueProvider;
+import org.apache.myfaces.trinidad.config.TestPropertyValueProvider;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+
+/**
+ *  This class allows access to configuration properties supplied by a plugable
+ *  property value provider.  Using a plugable property value provider separates
+ *  access to property values from where the values are stored, allowing different
+ *  property storage and configuration schemes to be used without impacting code
+ *  that uses the property values.
+ *  <p>
+ *  See {@link PropertyValueProvider PropertyValueProvider} for information
+ *  on configuring a property value provider.
+ */
+public final class ConfigPropertyServiceImpl
+  extends ConfigPropertyService
+{
+  /**
+   * Constructor.
+   */
+  private ConfigPropertyServiceImpl(List<PropertyValueProvider> valueProviders)
+  {
+    _valueProviders = new CopyOnWriteArrayList<PropertyValueProvider>(valueProviders);
+  }
+
+  @Override
+  public String getProperty(ExternalContext externalContext, String name)
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+
+    //
+    //  Iterate through the list of value providers and return the first non-null value
+    //  returned.
+    //
+    String result = null;
+    for (PropertyValueProvider provider: _valueProviders)
+    {
+      result = provider.getValue(externalContext, name);
+      if (result != null)
+      {
+        break;
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public void addPropertyChangeListener(PropertyChangeListener listener)
+  {
+    _changeListeners.add(listener);
+  }
+
+  @Override
+  public void removePropertyChangeListener(PropertyChangeListener listener)
+  {
+    _changeListeners.remove(listener);
+  }
+
+  @Override
+  protected synchronized TestPropertyValueProvider getTestProvider()
+  {
+    if (_testProvider == null)
+    {
+      _testProvider = new TestPropertyValueProvider();
+
+      //
+      //  Add the test provider to the front of the providers list so it's
+      //  checked first.
+      //
+      _valueProviders.add(0, _testProvider);
+    }
+    return _testProvider;
+  }
+
+  @Override
+  protected void notifyValueChange(ExternalContext externalContext, String name, String oldValue)
+  {
+    String newValue = getProperty(externalContext, name);
+    PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue);
+    for (PropertyChangeListener listener: _changeListeners)
+    {
+      listener.propertyChange(event);
+    }
+  }
+
+  /**
+   * This method initializes the collection of value providers.  The caller must ensure
+   * this method is called only once during the application's lifecycle to initialize the
+   * application's instance.
+   */
+  static void initialize(ExternalContext externalContext)
+  {
+    ArrayList<PropertyValueProvider> valueProviders = new ArrayList<PropertyValueProvider>(5);
+
+    //
+    //  The first value provider is always the servlet config value provider.
+    //
+    valueProviders.add(new ServletConfigValueProvider());
+
+    //
+    //  Next see if there is a value provider SPI registered on the classpath.
+    //
+    List<PropertyValueProvider> list = ClassLoaderUtils.getServices(_PROPERTY_PROVIDER_URL);
+    if (list.size() > 1)
+    {
+      throw new RuntimeException(_LOG.getMessage("MULTIPLE_CONFIG_PROPERTY_PROVIDERS_FOUND"));
+    }
+    else if (list.size() == 1)
+    {
+      valueProviders.add(list.get(0));
+    }
+
+    //
+    //  The last value provider is always the default value provider.
+    //
+    valueProviders.add(new DefaultValueProvider());
+
+    //
+    //  Create the instance and place it in the applicationScope map.
+    //
+    ConfigPropertyServiceImpl instance = new ConfigPropertyServiceImpl(valueProviders);
+    externalContext.getApplicationMap().put(ConfigPropertyService.CONFIG_PROPERTY_SERVICE_KEY, instance);
+  }
+
+  private TestPropertyValueProvider _testProvider = null;
+
+  private final List<PropertyValueProvider> _valueProviders;
+
+  private final Set<PropertyChangeListener> _changeListeners = new CopyOnWriteArraySet<PropertyChangeListener>();
+
+  static private final String _PROPERTY_PROVIDER_URL = "org.apache.myfaces.trinidad.config.PropertyValueProvider";
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ConfigPropertyServiceImpl.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ConfigPropertyServiceImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,58 @@
+/*
+ * 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.util.HashMap;
+import java.util.Map;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.config.PropertyValueProvider;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ * Provider of default configuration property values.  These values are what are returned
+ * when a value has not been specified by any other value provider.
+ */
+final class DefaultValueProvider
+  extends PropertyValueProvider
+{
+  public DefaultValueProvider()
+  {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getValue(ExternalContext extCtx, String name)
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+    String result = DEFAULT_VALUES.get(name);
+    return result;
+  }
+
+  //  Map of default config property name/value pairs.
+  private static final Map<String, String> DEFAULT_VALUES = new HashMap<String, String>();
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(DefaultValueProvider.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/DefaultValueProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java?rev=1588021&r1=1588020&r2=1588021&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java Wed Apr 16 18:38:28 2014
@@ -71,7 +71,7 @@ import org.apache.myfaces.trinidadintern
  * the Trindad developer.
  *
  * @see org.apache.myfaces.trinidad.config.Configurator
- * @version $Revision$ $Date$
+ * @version $Revision: daschnei_20131204_er17813713/3 $ $Date: 2014/01/21 13:53:38 $
  */
 public final class GlobalConfiguratorImpl
   extends Configurator
@@ -265,16 +265,16 @@ public final class GlobalConfiguratorImp
   @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())
+        if (_initialized.get())
         {
           for (final Configurator config: _services)
           {
@@ -317,7 +317,7 @@ public final class GlobalConfiguratorImp
     {
       try
       {
-         _endRequest(ec, state);
+        _endRequest(ec, state);
       }
       finally
       {
@@ -343,7 +343,7 @@ public final class GlobalConfiguratorImp
   {
     RequestStateMap state = RequestStateMap.getInstance(ec);
     RequestType type = (RequestType) state.get(_REQUEST_TYPE);
-    
+
     //Install the URLEncoder plugin system
     ec = new URLEncoderExternalContext(ec);
 
@@ -376,7 +376,7 @@ public final class GlobalConfiguratorImp
         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
@@ -384,7 +384,7 @@ public final class GlobalConfiguratorImp
     //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))
+    if (RequestType.ACTION.equals(type))
     {
       //We have an action, add the wrapper.
       ec = new RecordRedirectExternalContext(ec);
@@ -409,7 +409,7 @@ public final class GlobalConfiguratorImp
   public void init(ExternalContext ec)
   {
     assert ec != null;
-    
+
     if (!_initialized.get())
     {
       try
@@ -419,43 +419,46 @@ public final class GlobalConfiguratorImp
         //is checked again for validity.
         _initLock.lock();
         //Check the AtomicBoolean for a change
-        if(!_initialized.get())
-      {
-        _services = ClassLoaderUtils.getServices(Configurator.class.getName());
+        if (!_initialized.get())
+        {
+          _services = ClassLoaderUtils.getServices(Configurator.class.getName());
 
-        // set up the RequestContext Factory as needed.
-        _setupRequestContextFactory();
+          // set up the RequestContext Factory as needed.
+          _setupRequestContextFactory();
 
-        // Create a new SkinFactory if needed.
-        if (SkinFactory.getFactory() == null)
-        {
-          SkinFactory.setFactory(new SkinFactoryImpl());
-        }
+          // Create a new SkinFactory if needed.
+          if (SkinFactory.getFactory() == null)
+          {
+            SkinFactory.setFactory(new SkinFactoryImpl());
+          }
 
-        // init external skin provider
-        // this has to be done before SkinProviderRegistry, because SkinProviderRegistry uses this
-        Object externalSkinProvider = ec.getApplicationMap().get(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY);
+          // init external skin provider
+          // this has to be done before SkinProviderRegistry, because SkinProviderRegistry uses this
+          Object externalSkinProvider = ec.getApplicationMap().get(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY);
 
-        if (externalSkinProvider == null)
-          ec.getApplicationMap().put(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY, new ExternalSkinProvider());
+          if (externalSkinProvider == null)
+            ec.getApplicationMap().put(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY, new ExternalSkinProvider());
 
-        // init trinidad skin provider
-        // this has to be done before SkinProviderRegistry, because SkinProviderRegistry uses this
-        Object trinidadSkinProvider = ec.getApplicationMap().get(TrinidadSkinProvider.TRINDIAD_SKIN_PROVIDER_KEY);
+          // init trinidad skin provider
+          // this has to be done before SkinProviderRegistry, because SkinProviderRegistry uses this
+          Object trinidadSkinProvider = ec.getApplicationMap().get(TrinidadSkinProvider.TRINDIAD_SKIN_PROVIDER_KEY);
 
-        if (trinidadSkinProvider  == null)
-          ec.getApplicationMap().put(TrinidadSkinProvider.TRINDIAD_SKIN_PROVIDER_KEY, new TrinidadSkinProvider());
+          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);
+          // 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());
+          if (provider == null)
+            ec.getApplicationMap().put(SkinProvider.SKIN_PROVIDER_INSTANCE_KEY, new SkinProviderRegistry());
 
-        for (final Configurator config: _services)
-        {
-          config.init(ec);
-        }
+          // 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
@@ -509,7 +512,7 @@ public final class GlobalConfiguratorImp
   }
 
   /**
-   * Setup request context factory as needed. 
+   * Setup request context factory as needed.
    */
   private void _setupRequestContextFactory()
   {
@@ -517,7 +520,8 @@ public final class GlobalConfiguratorImp
       return;
 
     RequestContextFactory requestContextFactory = null;
-    List<RequestContextFactory> factories = ClassLoaderUtils.getServices(RequestContextFactory.class.getName());;    
+    List<RequestContextFactory> factories = ClassLoaderUtils.getServices(RequestContextFactory.class.getName());
+    ;
     if (factories.isEmpty())
       requestContextFactory = new RequestContextFactoryImpl();
     else
@@ -585,15 +589,16 @@ public final class GlobalConfiguratorImp
   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)))
+      if ((ExternalContextUtils.isResponseWritable(ec) || isRedirected) &&
+          !Boolean.TRUE.equals(state.get(_CONFIGURATORS_ABORTED)))
       {
         _endConfiguratorServices(ec);
       }
@@ -601,7 +606,7 @@ public final class GlobalConfiguratorImp
     finally
     {
       //If redirect was issued, we do not want to save the state.  Let it burn..  :D
-      if(!isRedirected)
+      if (!isRedirected)
       {
         state.saveState(ec);
       }
@@ -620,7 +625,7 @@ public final class GlobalConfiguratorImp
       _finishComponentReferenceInitialization(ec);
     }
   }
-  
+
   private void _releaseThreadLocals(ExternalContext ec)
   {
     try
@@ -663,26 +668,26 @@ public final class GlobalConfiguratorImp
   private void _finishComponentReferenceInitialization(ExternalContext ec)
   {
     Map<String, Object> requestMap = ec.getRequestMap();
-    
-    Collection<ComponentReference<?>> initializeList = (Collection<ComponentReference<?>>)
-                                             requestMap.get(_FINISH_INITIALIZATION_LIST_KEY);
-    
+
+    Collection<ComponentReference<?>> initializeList =
+      (Collection<ComponentReference<?>>) requestMap.get(_FINISH_INITIALIZATION_LIST_KEY);
+
     if ((initializeList != null) && !initializeList.isEmpty())
     {
       RuntimeException initializationException = null;
 
-      for (ComponentReference<?> reference : initializeList)
+      for (ComponentReference<?> reference: initializeList)
       {
         try
         {
-        reference.ensureInitialization();
-      }
+          reference.ensureInitialization();
+        }
         catch (RuntimeException rte)
         {
           initializationException = rte;
         }
       }
-      
+
       // we've initialized everything, so we're done
       initializeList.clear();
 
@@ -737,22 +742,22 @@ public final class GlobalConfiguratorImp
       }
     }
   }
-  
+
   private boolean _beginWindowManagerRequest(ExternalContext ec)
   {
     WindowManager wm = RequestContext.getCurrentInstance().getWindowManager();
-    boolean cont = true;  
-    
+    boolean cont = true;
+
     try
     {
       cont = wm.beginRequest(ec);
     }
-    catch(IOException e)
+    catch (IOException e)
     {
       _LOG.severe(e);
     }
-                        
-    return cont;                    
+
+    return cont;
   }
 
   static private boolean _isSetRequestBugPresent(ExternalContext ec)
@@ -788,7 +793,8 @@ public final class GlobalConfiguratorImp
   // This handles an issue with the ExternalContext object prior to
   // JSF1.2_04.
 
-  static private class ClearRequestExternalContext extends ExternalContextDecorator
+  static private class ClearRequestExternalContext
+    extends ExternalContextDecorator
   {
     private ExternalContext _ec;
     private Map<String, Object> _requestCookieMap;
@@ -884,8 +890,7 @@ public final class GlobalConfiguratorImp
       _checkRequest();
       if (_requestParameterValuesMap == null)
       {
-        _requestParameterValuesMap =
-            new ServletRequestParameterValuesMap((ServletRequest) getRequest());
+        _requestParameterValuesMap = new ServletRequestParameterValuesMap((ServletRequest) getRequest());
       }
       return _requestParameterValuesMap;
     }
@@ -910,66 +915,64 @@ public final class GlobalConfiguratorImp
     }
   }
 
-  static private class RecordRedirectExternalContext extends ExternalContextDecorator
+  static private class RecordRedirectExternalContext
+    extends ExternalContextDecorator
   {
     public RecordRedirectExternalContext(ExternalContext ec)
     {
-      assert(ec != null);
+      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 _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";
-  
+  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
   {
@@ -998,14 +1001,12 @@ public final class GlobalConfiguratorImp
   }
 
   // skanky duplication of key from ComponentReference Class
-  private static final String _FINISH_INITIALIZATION_LIST_KEY = ComponentReference.class.getName() +
-                                                                "#FINISH_INITIALIZATION";
+  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>();
+  private AtomicReference<ThreadLocalResetter> _threadResetter = new AtomicReference<ThreadLocalResetter>();
 
-  static private final TrinidadLogger _LOG =
-    TrinidadLogger.createTrinidadLogger(GlobalConfiguratorImpl.class);
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(GlobalConfiguratorImpl.class);
 }

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java?rev=1588021&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java Wed Apr 16 18:38:28 2014
@@ -0,0 +1,52 @@
+/*
+ * 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 javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.config.PropertyValueProvider;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ *  A {@link PropertyValueProvider PropertyValueProvider} that returns ServletContext
+ *  initialization parameter values.
+ */
+final class ServletConfigValueProvider
+  extends PropertyValueProvider
+{
+  ServletConfigValueProvider()
+  {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getValue(ExternalContext extCtx, String name)
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage("NULL_CONFIG_PROPERTY_NAME"));
+    }
+    String result = extCtx.getInitParameter(name);
+    return result;
+  }
+
+  static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ServletConfigValueProvider.class);
+}

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ServletConfigValueProvider.java
------------------------------------------------------------------------------
    svn:executable = *