001package gu.dtalk; 002 003import java.lang.reflect.Type; 004import java.util.Collection; 005import java.util.Observable; 006import com.alibaba.fastjson.annotation.JSONField; 007import com.google.common.base.MoreObjects; 008import com.google.common.base.Objects; 009import com.google.common.base.Predicate; 010import com.google.common.base.Predicates; 011 012import gu.dtalk.event.ValueChangeEvent; 013import gu.dtalk.event.ValueListener; 014 015import static com.google.common.base.Preconditions.*; 016 017/** 018 * 用于参数配置和命令参数的选项对象 019 * @author guyadong 020 * 021 * @param <T> 实例封装的数据类型 022 */ 023public abstract class BaseOption<T> extends BaseItem { 024 /** 025 * 选项值 026 */ 027 private T optionValue; 028 /** 029 * 选项默认值 030 */ 031 private T defaultValue; 032 /** 033 * 该选项是否为必须的 034 */ 035 private boolean required; 036 /** 037 * 该选项是否为只读的 038 */ 039 private boolean readOnly; 040 /** 041 * 当前选项的java类型 042 */ 043 protected final Type type; 044 /** 045 * 侦听器管理对象 046 */ 047 protected final Observable observable = new Observable(){ 048 @Override 049 public void notifyObservers(Object arg) { 050 setChanged(); 051 super.notifyObservers(arg); 052 } 053 }; 054 /** 055 * 数据值验证器,默认不验证直接返回true 056 */ 057 @JSONField(serialize = false,deserialize = false) 058 private Predicate<T> valueValidator = Predicates.alwaysTrue(); 059 public BaseOption(Type type) { 060 super(); 061 this.type = checkNotNull(type); 062 } 063 /** 064 * @return 当前选项的java类型 065 */ 066 public Type javaType(){ 067 return type; 068 } 069 /** 070 * @return 当前选项的类型 071 */ 072 public abstract OptionType getType(); 073 /** 074 * 设置当前选项的类型, 075 * 默认实现不会修改当前选项的类型 076 * @param type 077 * @return 当前对象 078 */ 079 BaseOption<T> setType(OptionType type){ 080 return this; 081 } 082 /** 083 * @return 该选项是否为只读的 084 */ 085 public boolean isReadOnly() { 086 return readOnly; 087 } 088 /** 089 * 设置该选项是否为只读的 090 * @param readOnly 091 * @return 当前对象 092 */ 093 public BaseOption<T> setReadOnly(boolean readOnly) { 094 this.readOnly = readOnly; 095 return this; 096 } 097 @Override 098 public final boolean isContainer() { 099 return false; 100 } 101 102 @Override 103 public final ItemType getCatalog() { 104 return ItemType.OPTION; 105 } 106 @Override 107 public final BaseItem addChilds(Collection<BaseItem> childs) { 108 // DO NOTHING 109 return this; 110 } 111 /** 112 * 验证value是否有效,该方法不会抛出异常 113 * @param value 114 * @return 成功返回true,否则返回false 115 */ 116 @SuppressWarnings("unchecked") 117 public boolean validate(Object value){ 118 try{ 119 return valueValidator.apply((T) value); 120 }catch (Exception e) { 121 return false; 122 } 123 } 124 /** 125 * @return 选项值 126 */ 127 public final T getValue() { 128 return optionValue; 129 } 130 /** 131 * 设置指定的值<br> 132 * 如果值有改变则向observer发送{@link ValueChangeEvent}消息 133 * @param value 134 * @return 当前对象 135 * @throws IllegalArgumentException 数值验证失败 136 * @see #validate(Object) 137 */ 138 public BaseOption<T> setValue(T value) { 139 if(!Objects.equal(value, optionValue)){ 140 optionValue = value; 141 observable.notifyObservers(new ValueChangeEvent<BaseOption<T>>(this)); 142 } 143 return this; 144 } 145 /** 146 * 更新选项的值,如果选项为只读(readonly)或value不满足条件({@link #validate(Object)})则抛出异常 147 * @param value 148 * @see #setValue(Object) 149 */ 150 public void updateFrom(T value){ 151 checkState(!isReadOnly(),"READONLY VALUE"); 152 checkArgument(validate(value),"INVALID VALUE"); 153 setValue(value); 154 } 155 /** 156 * 用选项req的值更新当前选项的值 157 * @param req 158 * @see #updateFrom(Object) 159 */ 160 public void updateFrom(BaseOption<T> req){ 161 if(req != null){ 162 // 设置参数 163 updateFrom(req.getValue()); 164 } 165 } 166 /** 167 * @return 返回缺省值 168 */ 169 public final T getDefaultValue() { 170 return defaultValue; 171 } 172 /** 173 * 设置默认值,同时验证数据有效性,失败抛出异常 174 * @param defaultValue 175 * @return 176 * @throws IllegalArgumentException 数值验证失败 177 * @see #validate(Object) 178 */ 179 public BaseOption<T> setDefaultValue(T defaultValue) { 180 checkArgument(null == defaultValue || validate(defaultValue),"INVALID DEFAULT VALUE"); 181 this.defaultValue = defaultValue; 182 return this; 183 } 184 /** 185 * 返回选项的值,如果为null则返回默认值 186 * @return 187 */ 188 public T fetch(){ 189 if(getValue() == null){ 190 return getDefaultValue(); 191 } 192 return getValue(); 193 } 194 /** 195 * 设置数据验证器 196 * @param validator 为null忽略 197 * @return 198 */ 199 public synchronized BaseOption<T> setValidator(Predicate<T> validator) { 200 if(validator != null){ 201 this.valueValidator = validator; 202 } 203 return this; 204 } 205 206 /** 207 * @return 该选项是否为必须的 208 */ 209 public boolean isRequired() { 210 return required; 211 } 212 213 /** 214 * 设置该选项是否为必须的 215 * @param required 216 * @return 当前对象 217 */ 218 public BaseOption<T> setRequired(boolean required) { 219 this.required = required; 220 return this; 221 } 222 /** 223 * @return 将选项的值转为用于显示的字符串 224 */ 225 public String contentOfValue(){ 226 return optionValue == null ? "": optionValue.toString(); 227 } 228 229 /** 230 * 以字符串形式设置值 231 * @param input 如果不符合数据类型的格式则抛出异常 232 * @return 233 * @see OptionType#trans() 234 */ 235 public BaseOption<T> asValue(String input){ 236 return setValue(getType().<T>trans().apply(input)); 237 } 238 /** 239 * 以字符串形式设置默认值 240 * @param input 如果不符合数据类型的格式则抛出异常 241 * @return 242 * @see OptionType#trans() 243 */ 244 public BaseOption<T> asDefaultValue(String input){ 245 return setDefaultValue(getType().<T>trans().apply(input)); 246 } 247 /** 248 * 检查value,defaultValue的有效性,无效则抛出异常 249 * @throws IllegalArgumentException value,defaultValue的值无效 250 */ 251 public BaseOption<T> compile(){ 252 // 检测value,defaultValue的值是否有效,无效则抛出异常 253 checkArgument(null == getValue() || validate(getValue()) 254 ,"CHECK:invalid value of %s",getType().name()); 255 checkArgument(null == getDefaultValue() || validate(getDefaultValue()) 256 ,"CHECK:invalid defaultValue of %s",getType().name()); 257 return this; 258 } 259 /** 260 * 添加事件侦听器 261 * @param listeners 262 * @return 263 */ 264 @SuppressWarnings("unchecked") 265 @SafeVarargs 266 public final BaseOption<T> addListener(ValueListener<T> ...listeners) { 267 for (ValueListener<T> listener : MoreObjects.firstNonNull(listeners, new ValueListener[0])) { 268 if(listener != null){ 269 this.observable.addObserver(listener); 270 } 271 } 272 return this; 273 } 274 275 @SuppressWarnings("unchecked") 276 @SafeVarargs 277 public final BaseOption<T> deleteListener(ValueListener<T> ...listeners) { 278 for (ValueListener<T> listener : MoreObjects.firstNonNull(listeners, new ValueListener[0])) { 279 if(listener != null){ 280 this.observable.deleteObserver(listener); 281 } 282 } 283 return this; 284 } 285 @Override 286 BaseOption<T> setParent(BaseItem parent) { 287 super.setParent(parent); 288 // 父类为CmdItem时,disable,readOnly属性无效 289 if(parent instanceof CmdItem){ 290 setDisable(false); 291 setReadOnly(false); 292 } 293 return this; 294 } 295}