    001    /*
    002     * Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved.
    003     *
    004     * Project and contact information: http://www.cascading.org/
    005     *
    006     * This file is part of the Cascading project.
    007     *
    008     * Licensed under the Apache License, Version 2.0 (the "License");
    009     * you may not use this file except in compliance with the License.
    010     * You may obtain a copy of the License at
    011     *
    012     *     http://www.apache.org/licenses/LICENSE-2.0
    013     *
    014     * Unless required by applicable law or agreed to in writing, software
    015     * distributed under the License is distributed on an "AS IS" BASIS,
    016     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    017     * See the License for the specific language governing permissions and
    018     * limitations under the License.
    019     */
    020
    021    package cascading.property;
    022
    023    import java.io.Serializable;
    024    import java.util.Collection;
    025    import java.util.Collections;
    026    import java.util.HashMap;
    027    import java.util.HashSet;
    028    import java.util.Map;
    029    import java.util.Set;
    030
    031    /**
    032     * The ConfigDef class allows for the creation of a configuration properties template to be applied to an existing
    033     * properties configuration set.
    034     * <p/>
    035     * There are three property modes, {@link Mode#DEFAULT}, {@link Mode#REPLACE}, and {@link Mode#UPDATE}.
    036     * <p/>
    037     * <ul>
    038     * <li>A DEFAULT property is only applied if there is no existing value in the property set.</li>
    039     * <li>A REPLACE property is always applied overriding any previous values.</li>
    040     * <li>An UPDATE property is always applied to an existing property. Usually when the property key represent a list of values.</li>
    041     * </ul>
    042     */
    043    public class ConfigDef implements Serializable
    044      {
    045      public enum Mode
    046        {
    047          DEFAULT, REPLACE, UPDATE
    048        }
    049
    050      public interface Setter
    051        {
    052        String set( String key, String value );
    053
    054        String update( String key, String value );
    055
    056        String get( String key );
    057        }
    058
    059      public interface Getter
    060        {
    061        String update( String key, String value );
    062
    063        String get( String key );
    064        }
    065
    066      protected Map<Mode, Map<String, String>> config;
    067
    068      public ConfigDef()
    069        {
    070        }
    071
    072      /**
    073       * Method setProperty sets the value to the given key using the {@link Mode#REPLACE} mode.
    074       *
    075       * @param key   the key
    076       * @param value the value
    077       * @return the current ConfigDef instance
    078       */
    079      public ConfigDef setProperty( String key, String value )
    080        {
    081        return setProperty( Mode.REPLACE, key, value );
    082        }
    083
    084      /**
    085       * Method setProperty sets the value to the given key using the given {@link Mode} value.
    086       *
    087       * @param key   the key
    088       * @param value the value
    089       * @return the current ConfigDef instance
    090       */
    091      public ConfigDef setProperty( Mode mode, String key, String value )
    092        {
    093        getMode( mode ).put( key, value );
    094
    095        return this;
    096        }
    097
    098      protected Map<String, String> getMode( Mode mode )
    099        {
    100        if( config == null )
    101          config = new HashMap<Mode, Map<String, String>>();
    102
    103        if( !config.containsKey( mode ) )
    104          config.put( mode, new HashMap<String, String>() );
    105
    106        return config.get( mode );
    107        }
    108
    109      protected Map<String, String> getModeSafe( Mode mode )
    110        {
    111        if( config == null )
    112          return Collections.EMPTY_MAP;
    113
    114        if( !config.containsKey( mode ) )
    115          return Collections.EMPTY_MAP;
    116
    117        return config.get( mode );
    118        }
    119
    120      /**
    121       * Returns {@code true} if there are no properties.
    122       *
    123       * @return true if no properties.
    124       */
    125      public boolean isEmpty()
    126        {
    127        return config == null || config.isEmpty();
    128        }
    129
    130      public String apply( String key, Getter getter )
    131        {
    132        String defaultValue = getModeSafe( Mode.DEFAULT ).get( key );
    133        String replaceValue = getModeSafe( Mode.REPLACE ).get( key );
    134        String updateValue = getModeSafe( Mode.UPDATE ).get( key );
    135
    136        String currentValue = getter.get( key );
    137
    138        if( currentValue == null && replaceValue == null && updateValue == null )
    139          return defaultValue;
    140
    141        if( replaceValue != null )
    142          return replaceValue;
    143
    144        if( updateValue == null )
    145          return currentValue;
    146
    147        if( currentValue == null )
    148          return updateValue;
    149
    150        return getter.update( key, updateValue );
    151        }
    152
    153      public void apply( Mode mode, Setter setter )
    154        {
    155        if( !config.containsKey( mode ) )
    156          return;
    157
    158        for( String key : config.get( mode ).keySet() )
    159          {
    160          switch( mode )
    161            {
    162            case DEFAULT:
    163              if( setter.get( key ) == null )
    164                setter.set( key, config.get( mode ).get( key ) );
    165              break;
    166            case REPLACE:
    167              setter.set( key, config.get( mode ).get( key ) );
    168              break;
    169            case UPDATE:
    170              setter.update( key, config.get( mode ).get( key ) );
    171              break;
    172            }
    173          }
    174        }
    175
    176      public Collection<String> getAllKeys()
    177        {
    178        Set<String> keys = new HashSet<String>();
    179
    180        for( Map<String, String> map : config.values() )
    181          keys.addAll( map.keySet() );
    182
    183        return Collections.unmodifiableSet( keys );
    184        }
    185      }