根据用户名获得用户状态时对用户进行锁定(有线程重入的可能)
[vxsms:smsservice.git] / src / org / vxwo / oss / smsservice / flowhander / AbstractServiceHandler.java
1 package org.vxwo.oss.smsservice.flowhander;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.List;\r
5 \r
6 import org.apache.commons.logging.Log;\r
7 import org.apache.commons.logging.LogFactory;\r
8 import org.vxwo.oss.smsserver.webservice.soap.SmsMoMsg;\r
9 import org.vxwo.oss.smsserver.webservice.soap.SmsMtMsg;\r
10 import org.vxwo.oss.smsservice.engine.ISmsHandler;\r
11 import org.vxwo.oss.smsservice.engine.IStartup;\r
12 import org.vxwo.oss.smsservice.engine.ProcessEngine;\r
13 import org.vxwo.oss.smsservice.flowhander.function.FuncEmpty;\r
14 import org.vxwo.oss.smsservice.flowhander.function.FuncInvalidUser;\r
15 import org.vxwo.oss.smsservice.flowhander.function.FuncInvalidUserMessage;\r
16 import org.vxwo.oss.smsservice.flowhander.function.FuncJump;\r
17 import org.vxwo.oss.smsservice.flowhander.function.FuncSendMessage;\r
18 import org.vxwo.oss.smsservice.flowhander.script.Action;\r
19 import org.vxwo.oss.smsservice.flowhander.script.Command;\r
20 import org.vxwo.oss.smsservice.flowhander.script.Flow;\r
21 import org.vxwo.oss.smsservice.flowhander.script.FlowTable;\r
22 import org.vxwo.oss.smsservice.flowhander.script.FlowTableReader;\r
23 import org.vxwo.oss.smsservice.flowhander.script.FunctionTable;\r
24 import org.vxwo.oss.smsservice.flowhander.script.State;\r
25 \r
26 public abstract class AbstractServiceHandler implements IStartup, ISmsHandler {\r
27 \r
28         protected static class AnalyzeUserResult {\r
29 \r
30                 private boolean result;\r
31                 private String state;\r
32 \r
33                 public AnalyzeUserResult() {\r
34                 }\r
35 \r
36                 public boolean isResult() {\r
37                         return result;\r
38                 }\r
39 \r
40                 public void setResult(boolean result) {\r
41                         this.result = result;\r
42                 }\r
43 \r
44                 public String getState() {\r
45                         return state;\r
46                 }\r
47 \r
48                 public void setState(String state) {\r
49                         this.state = state;\r
50                 }\r
51 \r
52         }\r
53 \r
54         /**\r
55          * 创建新用户\r
56          * \r
57          * @return\r
58          */\r
59         protected abstract AbstractUserState newUserState();\r
60 \r
61         /**\r
62          * 分析获得ServiceId\r
63          * \r
64          * @return\r
65          */\r
66         protected abstract int analyzeServiceId(AbstractUserState user);\r
67 \r
68         /**\r
69          * 分析获得用户状态信息\r
70          * \r
71          * @return\r
72          */\r
73         protected abstract AbstractUserState analyzeUserState(String username);\r
74 \r
75         /**\r
76          * 处理用户\r
77          * \r
78          * @param user\r
79          * @param newUser\r
80          *            是否为新用户\r
81          * @return\r
82          */\r
83         protected abstract AnalyzeUserResult doAnalyzeUser(AbstractUserState user,\r
84                         boolean newUser);\r
85 \r
86         public static Log log = LogFactory.getLog("SERVICE");\r
87 \r
88         private ProcessEngine process;\r
89         private FlowTable flowTable;\r
90         private FunctionTable funcTable = new FunctionTable();\r
91         private UserStateManager userManager = new UserStateManager();\r
92 \r
93         public AbstractServiceHandler() {\r
94                 process = new ProcessEngine(this);\r
95                 addFunction("Jump", new FuncJump());\r
96                 addFunction("Empty", new FuncEmpty());\r
97                 addFunction("InvalidUser", new FuncInvalidUser());\r
98                 addFunction("SendMessage", new FuncSendMessage());\r
99                 addFunction("InvalidUserMessage", new FuncInvalidUserMessage());\r
100         }\r
101 \r
102         public void startup() throws Exception {\r
103                 flowTable = FlowTableReader.newInstance(funcTable).loadFlowTable(\r
104                                 "workflow.xml");\r
105                 process.startup();\r
106         }\r
107 \r
108         public void addFunction(String name, AbstractFunction function) {\r
109                 function.setHandler(this);\r
110                 funcTable.addFunction(name, function);\r
111         }\r
112 \r
113         public Flow findFlow(String code) {\r
114                 return flowTable.findFlow(code);\r
115         }\r
116 \r
117         public void delUserState(String username) {\r
118                 userManager.delUserState(username);\r
119         }\r
120 \r
121         public void sendMessage(SmsMtMsg mtMsg) {\r
122                 if (mtMsg.getServiceId() == 0) {\r
123                         // 分析用户实际的serviceId\r
124                         AbstractUserState user = null;\r
125                         String username = mtMsg.getDestTermId();\r
126                         // 多线程情况下用户状态串行分析\r
127                         synchronized (userManager.getUserLocker(username)) {\r
128                                 user = userManager.getUserState(username);\r
129                                 if (user == null) {\r
130                                         user = analyzeUserState(username);\r
131                                         if (user != null)\r
132                                                 userManager.addUserState(user);\r
133                                 }\r
134                         }\r
135                         mtMsg.setServiceId(analyzeServiceId(user));\r
136                 }\r
137                 process.sendMessage(mtMsg);\r
138         }\r
139 \r
140         public void testMessage(SmsMoMsg moMsg) {\r
141                 process.testMessage(moMsg);\r
142         }\r
143 \r
144         public void handle(SmsMoMsg moMsg) {\r
145                 String username = moMsg.getSrcTermId();\r
146                 // 多线程情况下用户上行串行处理\r
147                 synchronized (userManager.getUserLocker(username)) {\r
148                         // 获得用户状态\r
149                         AbstractUserState user = userManager.getUserState(username);\r
150                         AnalyzeUserResult result = null;\r
151                         if (user == null) {\r
152                                 // 创建新用户\r
153                                 user = newUserState();\r
154                                 user.setUsername(username);\r
155                                 user.setCurState("begin");\r
156                                 user.setCurCalled(moMsg.getDestTermId());\r
157                                 user.setCurServerId(new Integer(moMsg.getServiceId()));\r
158                                 user.setSmsContent(moMsg.getContent());\r
159                                 user.setCurLinkId(moMsg.getLinkId());\r
160                                 // 处理用户状态\r
161                                 result = doAnalyzeUser(user, true);\r
162                                 if (result.isResult())\r
163                                         userManager.addUserState(user);// 添加用户缓存信息\r
164                         } else {\r
165                                 user.setPreCalled(user.getCurCalled());\r
166                                 user.setCurCalled(moMsg.getDestTermId());\r
167                                 user.setPreServerId(user.getCurServerId());\r
168                                 user.setCurServerId(new Integer(moMsg.getServiceId()));\r
169                                 user.setSmsContent(moMsg.getContent());\r
170                                 // 始终保留最后一次有效LinkId\r
171                                 if (user.getCurLinkId() != null\r
172                                                 && !user.getCurLinkId().isEmpty())\r
173                                         user.setPreLinkId(user.getCurLinkId());\r
174                                 user.setCurLinkId(moMsg.getLinkId());\r
175                                 // 处理用户状态\r
176                                 result = doAnalyzeUser(user, false);\r
177                                 if (result.isResult())\r
178                                         userManager.modUserState(user);// 更新用户缓存信息\r
179                         }\r
180                         // 检查忽略此次流程\r
181                         if (!result.isResult() || result.getState() == null) {\r
182                                 log.warn("Lost Msg: [" + moMsg.getServiceId() + "]["\r
183                                                 + moMsg.getSrcTermId() + "][" + moMsg.getDestTermId()\r
184                                                 + "][" + moMsg.getContent() + "][" + moMsg.getLinkId()\r
185                                                 + "]");\r
186                                 return;\r
187                         }\r
188                         // 获得指令对应流程\r
189                         Flow flow = flowTable.findFlow(user.getSmsContent());\r
190                         if (flow != null) {\r
191                                 user.setFlow(flow);\r
192                                 user.setCurState("begin");\r
193                         } else if (user.getFlow() == null) {\r
194                                 // 读取默认流程\r
195                                 flow = flowTable.findFlow("[DEFAULT]");\r
196                                 if (flow != null) {\r
197                                         user.setFlow(flow);\r
198                                         user.setCurState("begin");\r
199                                 }\r
200                         }\r
201                         // 用户流程处理\r
202                         List<String> msgs = new ArrayList<String>();\r
203                         msgs.add(result.getState());\r
204                         while (msgs.size() > 0) {\r
205                                 // 读一条文本\r
206                                 String msg = (String) msgs.remove(0);\r
207                                 // 流程处理\r
208                                 try {\r
209                                         dispatchToFlow(user, msg, msgs);\r
210                                 } catch (Exception e) {\r
211                                         if (log.isWarnEnabled())\r
212                                                 log.warn(e);\r
213                                         break; // 出现异常就退出处理\r
214                                 }\r
215                         }\r
216                         // 更新用户缓存信息\r
217                         userManager.modUserState(user);\r
218                 }\r
219         }\r
220 \r
221         /**\r
222          * 流程状态处理\r
223          * \r
224          * @param user\r
225          * @param cmd\r
226          * @throws Exception\r
227          */\r
228         protected void dispatchToFlow(AbstractUserState user, String cmd,\r
229                         List<String> cmds) throws Exception {\r
230                 // 读取用户的流程对象\r
231                 Flow flow = user.getFlow();\r
232                 if (flow == null)\r
233                         throw new IllegalArgumentException("Flow [" + user.getUsername()\r
234                                         + "] not found");\r
235                 State state = flow.findState(user.getCurState());\r
236                 if (state == null)\r
237                         throw new IllegalArgumentException("Flow [" + user.getUsername()\r
238                                         + "] [" + flow.getCode() + "] not found state ["\r
239                                         + user.getCurState() + "]");\r
240                 Command command = state.findCommand(cmd);\r
241                 if (command == null)\r
242                         throw new IllegalArgumentException("Flow [" + user.getUsername()\r
243                                         + "] [" + flow.getCode() + "] [" + user.getCurState()\r
244                                         + "] not found command [" + cmd + "]");\r
245                 // 设置下一状态名\r
246                 user.setNextState(command.getNextState());\r
247                 // 调用Action\r
248                 for (int i = 0, n = command.getActionCount(); i < n; i++) {\r
249                         Action action = command.getAction(i);\r
250                         user.setPreContent(user.getCurContent());\r
251                         if (!action.getContent().isEmpty())\r
252                                 user.setCurContent(action.getContent());\r
253                         // 调用处理函数\r
254                         ((AbstractFunction) action.getFunction()).invoke(user, cmd, cmds);\r
255                 }\r
256                 // 更新用户状态\r
257                 user.setPreState(user.getCurState());\r
258                 user.setCurState(user.getNextState());\r
259         }\r
260 }