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}