shikeying
2024-01-11 3b67e947e36133e2a40eb2737b15ea375e157ea0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package com.walker.infrastructure.arguments;
 
import com.walker.infrastructure.arguments.support.DefaultVariable;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.security.SystemLogMan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * 抽象的参数管理器实现。
 * @author shikeying
 *
 */
public abstract class AbstractArgumentsManager implements ArgumentsManager {
 
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
    private Object source;
    
    /* 分组集合 */
    private Map<String, Group> groupMap = new TreeMap<String, Group>();
    
    /* 变量集合与组ID映射关系:key=groupId, value=variable ID set */
    private ConcurrentHashMap<String, List<String>> variableMap = new ConcurrentHashMap<String, List<String>>(8);
    
    private ConcurrentHashMap<String, Variable> allVars = new ConcurrentHashMap<String, Variable>(32);
    
    private Object lock = new Object();
    
    @Override
    public void setSource(Object source){
        assert (source != null);
        this.source = source;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception{
        SystemLogMan.getInstance().checkMan();
//        if(this.source == null){
//            throw new ArgumentsException("parameter: source is not found!");
//        }
        
        List<Group> groupList = null;
        
        try{
            groupList = load(source);
        } catch(Exception ex){
            throw new ArgumentsException("业务加载配置参数失败:" + ex.getMessage(), ex);
        }
        
        initGroup(groupList);
        
        if(logger.isDebugEnabled()){
            logger.debug("~~~~~~~~~~~~~~~~~ 系统加载所有配置参数-start ~~~~~~~~~~~~~~~~~");
            for(Variable v : allVars.values()){
                logger.debug(v.toString());
            }
            logger.debug("~~~~~~~~~~~~~~~~~ 系统加载所有配置参数-end ~~~~~~~~~~~~~~~~~");
        }
    }
    
    private void initGroup(List<Group> groupList){
        if(groupList != null){
            Collections.sort(groupList);
            for(Group g : groupList){
                groupMap.put(g.getId(), g);
                initVariableInGroup(g);
            }
        }
    }
    
    private void initVariableInGroup(Group group){
        List<Variable> varList = group.getChildren();
        if(varList != null && varList.size() > 0){
            List<String> varIds = new ArrayList<String>(8);
            for(Variable v : varList){
                allVars.put(v.getId(), v);
                varIds.add(v.getId());
            }
            variableMap.put(group.getId(), varIds);
        } else
            variableMap.put(group.getId(), null);
    }
    
    /**
     * 加载具体的参数数据,并返回分组集合信息,分组中包含了可变参数数据。</p>
     * 子类实现具体加载过程。
     * @param source 输入参数,由业务设置加载数据的原始参数,如:xml文件、数据源等。
     * @return
     */
    protected abstract List<Group> load(Object source) throws Exception;
    
    /**
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * 以下为系统提供的标准API
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    
    @Override
    public Variable getVariable(String id) {
        assert (StringUtils.isNotEmpty(id));
        Variable var = allVars.get(id);
        if(var == null)
            throw new ElementNotFoundException("variable not found: " + id);
        return var;
    }
 
    @Override
    public void persist(String variableId, Object value) {
        if(groupMap.size() > 1)
            throw new ArgumentsException("存在多个分组,请调用方法: persist(String groupId, String variableId, Object value)");
        String groupId = groupMap.keySet().iterator().next();
        persist(groupId, variableId, value);
    }
 
    @Override
    public void persist(String groupId, String variableId, Object value) {
        assert (StringUtils.isNotEmpty(groupId));
        assert (value != null);
        
        /* 更新实体中的数据 */
        try {
            saveVariable(groupId, variableId, value);
        } catch (Exception e) {
            throw new ArgumentsException("更新可变参数到业务中出现错误: " + e.getMessage(), e);
        }
        
        synchronized (lock) {
            updateCache(groupId, variableId, value);
        }
    }
    
    private void updateCache(String groupId, String variableId, Object value){
        if(groupMap.get(groupId) == null)
            throw new IllegalArgumentException("not found group id: " + groupId);
        List<String> existVarSet = variableMap.get(groupId);
        if(existVarSet == null)
            throw new ArgumentsException("not found variable in cache: " + variableId);
        if(existVarSet.contains(variableId)){
            // 暂时先强制转换成具体对象,调用更改值的方法,后续扩充时需要注意,可能会不合适。
            DefaultVariable current = (DefaultVariable)allVars.get(variableId);
            current.setValue(value);
        } else
            throw new ElementNotFoundException("var id: " + variableId);
    }
    
    @Override
    public void persist(List<Object[]> changedList){
        if(changedList == null) return;
        for(Object[] arr : changedList){
            if(arr.length != 3)
                throw new IllegalArgumentException("输入参数不正确,集合中为数组,每个数组需要三个元素: groupId, variableId, value.");
            if(StringUtils.isEmpty(arr[0].toString()))
                throw new IllegalArgumentException("第一个参数:groupId不存在或者是空值");
            if(StringUtils.isEmpty(arr[1].toString()))
                throw new IllegalArgumentException("第二个参数:variableId不存在或者是空值");
            if(arr[2] == null)
                throw new IllegalArgumentException("第三个参数:value不存在或者是空值");
        }
        
        /* 更新实体中的数据 */
        try {
            saveVariables(changedList);
        } catch (Exception e) {
            throw new ArgumentsException("更新可变参数到业务中出现错误: " + e.getMessage(), e);
        }
        
        synchronized (lock){
            for(Object[] args : changedList){
                updateCache(args[0].toString(), args[1].toString(), args[2]);
            }
        }
    }
    
    @Override
    public void insert(List<Object[]> insertList) {
        if(insertList == null) return;
        for(Object[] arr : insertList){
            if(arr.length != 2)
                throw new IllegalArgumentException("输入参数不正确,集合中为数组,每个数组需要两个元素: group, variable.");
            if(StringUtils.isEmpty(arr[0].toString()))
                throw new IllegalArgumentException("第一个参数:group不存在或者是空值");
            if(StringUtils.isEmpty(arr[1].toString()))
                throw new IllegalArgumentException("第二个参数:variable不存在或者是空值");
        }
        /* 更新实体中的数据 */
        try {
            insertVariables(insertList);
        } catch (Exception e) {
            throw new ArgumentsException("新建可变参数出现错误: " + e.getMessage(), e);
        }
        
        synchronized (lock){
            for(Object[] args : insertList){
                insertCache((Group)args[0], (Variable)args[1]);
            }
        }
    }
    
    /**
     * 由子类来实现具体的更新介质中的参数,如:数据库、配置文件等。
     * @param groupId 分组ID
     * @param variableId 可变参数ID
     * @param value 更新的值
     * @throws Exception
     */
    protected abstract void saveVariable(String groupId
            , String variableId, Object value) throws Exception;
    
    /**
     * 子类实现持久化更新参数信息到介质中,如:数据库、配置文件等。</p>
     * 批量更新方法,集合中是数组对象,Object[]{groupId, variableId, value}</br>
     * 即:分组ID、可变参数ID、更新的值。
     * @param changedList 需要更新的参数集合。
     * @throws Exception
     */
    protected abstract void saveVariables(List<Object[]> changedList) throws Exception;
    
    /**
     * 加入新的参数集合,集合中是数组对象,Object[]{group, variable}
     * 如果已经存在该参数,则不再创建。
     * @param insertList
     * @throws Exception
     */
    protected abstract void insertVariables(List<Object[]> insertList) throws Exception;
 
    private void insertCache(Group group, Variable variable){
        assert (group != null);
        assert (variable != null);
        if(!groupMap.containsKey(group.getId())){
            groupMap.put(group.getId(), group);
        }
        if(!allVars.containsKey(variable.getId())){
            // 不包含才加入到缓存
            allVars.put(variable.getId(), variable);
            List<String> varList = variableMap.get(group.getId());
            if(varList == null){
                varList = new ArrayList<String>(2);
                variableMap.put(group.getId(), varList);
            }
            varList.add(variable.getId());
        }
    }
    
    @Override
    public List<Group> getGroupList() {
        if(groupMap.size() == 0) return null;
        List<Group> list = new ArrayList<Group>(8);
        for(Iterator<Group> it = groupMap.values().iterator(); it.hasNext();){
            list.add(it.next());
        }
        Collections.sort(list);
        return list;
    }
 
    @Override
    public List<Variable> getVariableList(String groupId) {
        assert (StringUtils.isNotEmpty(groupId));
        if(groupMap.size() == 0){
            return null;
        }
        List<String> varIds = variableMap.get(groupId);
        if(varIds == null)
            return null;
        
        List<Variable> result = new ArrayList<Variable>(8);
        Variable var = null;
        for(String vid : varIds){
            var = allVars.get(vid);
            if(var == null) throw new ElementNotFoundException("var id: " + vid);
            result.add(var);
        }
        return result;
    }
 
    @Override
    public void destroy() throws Exception{
        this.source = null;
        this.groupMap.clear();
        this.variableMap.clear();
        this.allVars.clear();
    }
}