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 }