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
019package org.apache.hadoop.conf;
020
021import org.apache.commons.logging.*;
022
023import 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 */
032public 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}