001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.conf;
020    
021    import org.apache.commons.logging.*;
022    
023    import java.util.Collection;
024    
025    /**
026     * Utility base class for implementing the Reconfigurable interface.
027     *
028     * Subclasses should override reconfigurePropertyImpl to change individual
029     * properties and getReconfigurableProperties to get all properties that
030     * can be changed at run time.
031     */
032    public abstract class ReconfigurableBase 
033      extends Configured implements Reconfigurable {
034      
035      private static final Log LOG =
036        LogFactory.getLog(ReconfigurableBase.class);
037    
038      /**
039       * Construct a ReconfigurableBase.
040       */
041      public ReconfigurableBase() {
042        super(new Configuration());
043      }
044    
045      /**
046       * Construct a ReconfigurableBase with the {@link Configuration}
047       * conf.
048       */
049      public ReconfigurableBase(Configuration conf) {
050        super((conf == null) ? new Configuration() : conf);
051      }
052    
053      /**
054       * {@inheritDoc}
055       *
056       * This method makes the change to this objects {@link Configuration}
057       * and calls reconfigurePropertyImpl to update internal data structures.
058       * This method cannot be overridden, subclasses should instead override
059       * reconfigureProperty.
060       */
061      @Override
062      public final String reconfigureProperty(String property, String newVal) 
063        throws ReconfigurationException {
064        if (isPropertyReconfigurable(property)) {
065          LOG.info("changing property " + property + " to " + newVal);
066          String oldVal;
067          synchronized(getConf()) {
068            oldVal = getConf().get(property);
069            reconfigurePropertyImpl(property, newVal);
070            if (newVal != null) {
071              getConf().set(property, newVal);
072            } else {
073              getConf().unset(property);
074            }
075          }
076          return oldVal;
077        } else {
078          throw new ReconfigurationException(property, newVal,
079                                                 getConf().get(property));
080        }
081      }
082    
083      /**
084       * {@inheritDoc}
085       *
086       * Subclasses must override this.
087       */
088      @Override 
089      public abstract Collection<String> getReconfigurableProperties();
090    
091    
092      /**
093       * {@inheritDoc}
094       *
095       * Subclasses may wish to override this with a more efficient implementation.
096       */
097      @Override
098      public boolean isPropertyReconfigurable(String property) {
099        return getReconfigurableProperties().contains(property);
100      }
101    
102      /**
103       * Change a configuration property.
104       *
105       * Subclasses must override this. This method applies the change to
106       * all internal data structures derived from the configuration property
107       * that is being changed. If this object owns other Reconfigurable objects
108       * reconfigureProperty should be called recursively to make sure that
109       * to make sure that the configuration of these objects is updated.
110       */
111      protected abstract void reconfigurePropertyImpl(String property, String newVal) 
112        throws ReconfigurationException;
113    
114    }