1
2
3
4
5
6 package net.kwfgrid.gwui.workflow;
7
8 import net.kwfgrid.gworkflowdl.protocol.IncompatibleVersionsException;
9 import net.kwfgrid.gworkflowdl.protocol.IllegalModificationException;
10 import net.kwfgrid.gworkflowdl.protocol.IModificationHandler;
11 import net.kwfgrid.gworkflowdl.protocol.IMethodCallEncoder;
12 import net.kwfgrid.gworkflowdl.protocol.AbstractMethodCallStrategyExt;
13 import net.kwfgrid.gworkflowdl.protocol.Protocol;
14 import net.kwfgrid.gworkflowdl.protocol.service.IStructureService;
15 import net.kwfgrid.gworkflowdl.protocol.calls.MethodCallException;
16 import net.kwfgrid.gworkflowdl.protocol.calls.IMethodCall;
17 import net.kwfgrid.gworkflowdl.protocol.structure.IStructureTask;
18 import net.kwfgrid.gworkflowdl.protocol.structure.ProtocolWorkflow;
19 import net.kwfgrid.gworkflowdl.protocol.client.*;
20 import net.kwfgrid.gworkflowdl.structure.WorkflowFormatException;
21 import net.kwfgrid.gworkflowdl.structure.CapacityException;
22
23 import java.rmi.RemoteException;
24 import java.io.IOException;
25 import java.util.*;
26
27 import org.apache.log4j.Logger;
28
29 import org.glassbox.SwingThread;
30
31 /***
32 Implementation of <code>IClientDelegate</code> which handles all modifications of
33 the structure on the Swing Event Dispatch Thread.
34 */
35 public class SwingClientDelegateExt extends AbstractMethodCallStrategyExt implements IClientDelegate {
36 private static class CallExecution implements Runnable {
37 private IClientRootObject _structure;
38 private SwingClientDelegateExt _clientdelegate;
39 private IMethodCall _call;
40 private Object _returnvalue;
41 private Throwable _exception;
42
43 public CallExecution(SwingClientDelegateExt clientdelegate, IClientRootObject structure) {
44 _clientdelegate = clientdelegate;
45 _structure = structure;
46 _call = null;
47 _returnvalue = null;
48 _exception = null;
49 }
50
51 public void setCall(IMethodCall call) {
52 _call = call;
53 _exception = null;
54 _returnvalue = null;
55 }
56
57 public Object getReturnValue() {
58 return _returnvalue;
59 }
60
61 public Throwable getException() {
62 return _exception;
63 }
64
65 public boolean exceptionOccured() {
66 return _exception != null;
67 }
68
69 public void run() {
70 _clientdelegate.fireBeginModifications(_structure);
71
72 try {
73 _returnvalue = _call.execute();
74 } catch (Exception x) {
75 _clientdelegate.fireException(_structure, x);
76 _exception = x;
77 }
78
79 _clientdelegate.fireEndModifications(_structure);
80 }
81 }
82
83 private static class UpdateExecution implements Runnable {
84 private IClientRootObject _structure;
85 private SwingClientDelegateExt _clientdelegate;
86 private String[][] _updates;
87 private Throwable _exception;
88
89 public UpdateExecution(SwingClientDelegateExt clientdelegate, IClientRootObject structure) {
90 _clientdelegate = clientdelegate;
91 _structure = structure;
92 _exception = null;
93 _updates = null;
94 }
95
96 public void setUpdates(String[][] updates) {
97 _updates = updates;
98 _exception = null;
99 }
100
101 public Throwable getException() {
102 return _exception;
103 }
104
105 public boolean exceptionOccured() {
106 return _exception != null;
107 }
108
109 public void run() {
110 _clientdelegate.fireBeginModifications(_structure);
111
112 try {
113 for (int i=0; i<_updates.length; i++) {
114 String version = _updates[i][0];
115 String command = _updates[i][1];
116 String content = _updates[i][2];
117 _clientdelegate.handleUpdate(_structure, command, content);
118 _structure.setVersionNumber(Integer.parseInt(version));
119 }
120 } catch (IllegalModificationException x) {
121 _clientdelegate.fireException(_structure, x);
122 _exception = x;
123 } catch (NumberFormatException x) {
124 _clientdelegate.fireException(_structure, x);
125 _exception = new IllegalModificationException("Could not parse version number as string.", x);
126 }
127
128 _clientdelegate.fireEndModifications(_structure);
129 }
130 }
131
132 private static final Logger logger = Logger.getLogger(SwingClientDelegateExt.class);
133
134 private IStructureService _servicestub;
135
136 private HashMap _callexecutions;
137 private HashMap _updateexecutions;
138
139 /***
140 Constructor.
141 @param servicestub The service stub to contact the server.
142 */
143 public SwingClientDelegateExt(IStructureService servicestub) {
144 _servicestub = servicestub;
145 _callexecutions = new HashMap();
146 _updateexecutions = new HashMap();
147 }
148
149 private CallExecution getCallExecution(IClientRootObject structure) {
150 CallExecution exe = (CallExecution)_callexecutions.get(structure);
151 if (exe == null) {
152 exe = new CallExecution(this, structure);
153 _callexecutions.put(structure, exe);
154 }
155 return exe;
156 }
157
158 private UpdateExecution getUpdateExecution(IClientRootObject structure) {
159 UpdateExecution exe = (UpdateExecution)_updateexecutions.get(structure);
160 if (exe == null) {
161 exe = new UpdateExecution(this, structure);
162 _updateexecutions.put(structure, exe);
163 }
164 return exe;
165 }
166
167 public Object execute(IMethodCall call) throws MethodCallException, IllegalModificationException, IncompatibleVersionsException {
168 IClientRootObject structure = (IClientRootObject)call.getTarget();
169 IMethodCallEncoder encoder = Protocol.getMethodCallEncoder();
170 String enc = null;
171 Object ret = null;
172 IStructureTask tasks[] = null;
173
174 synchronized(structure.getStructureLock()) {
175 try {
176 enc = encoder.encode(call);
177 } catch (IOException x) {
178 IllegalModificationException ix = new IllegalModificationException("Could not encode method call.");
179 ix.initCause(x);
180 throw ix;
181 }
182 try {
183 commit(structure, enc);
184 } catch (RemoteException x) {
185 IllegalModificationException ix = new IllegalModificationException("Could not commit changes. Exception on server-side.");
186 ix.initCause(x);
187 throw ix;
188 }
189
190 CallExecution exe = getCallExecution(structure);
191 exe.setCall(call);
192
193
194
195
196 SwingThread.invokeAndWaitSilently(exe);
197
198 if (exe.exceptionOccured()) {
199 throw new MethodCallException("Could not invoke method call. Structure invalid and needs to be checked out again.", exe.getException());
200 }
201
202 ret = exe.getReturnValue();
203
204 List queue = structure.getTaskQueue();
205 tasks = (IStructureTask[])queue.toArray(new IStructureTask[queue.size()]);
206 queue.clear();
207 }
208
209 try {
210 for (int i=0; i<tasks.length; i++) {
211 tasks[i].run();
212 }
213 } catch (IncompatibleVersionsException x) {
214 IncompatibleVersionsException ix = new IncompatibleVersionsException("Nested IncompatibleVersionsException.", x);
215 throw ix;
216 } catch (IllegalModificationException x) {
217 IllegalModificationException ix = new IllegalModificationException("Nested IllegalModificationException.", x);
218 throw ix;
219 } catch (Exception x) {
220 throw new MethodCallException("Could not execute inner method call.", x);
221 }
222
223 return ret;
224 }
225
226 public void commit(IClientRootObject structure, String modification) throws IllegalModificationException, IncompatibleVersionsException, RemoteException {
227 synchronized (structure.getStructureLock()) {
228 int newversion = _servicestub.commitModification(structure.getID(), structure.getVersionNumber(), modification);
229 structure.setVersionNumber(newversion);
230 }
231 }
232
233 public void update(IClientRootObject structure) throws IllegalModificationException, RemoteException {
234 IStructureTask tasks[] = null;
235
236 synchronized (structure.getStructureLock()) {
237
238 String[][] updates = _servicestub.getModificationsForUpdate(structure.getID(), structure.getVersionNumber());
239
240 if (updates.length > 0) {
241
242 UpdateExecution exe = getUpdateExecution(structure);
243 exe.setUpdates(updates);
244 SwingThread.invokeAndWaitSilently(exe);
245
246 if (exe.exceptionOccured()) {
247 throw (IllegalModificationException)exe.getException();
248 }
249
250 List queue = structure.getTaskQueue();
251 tasks = (IStructureTask[])queue.toArray(new IStructureTask[queue.size()]);
252 queue.clear();
253 }
254 }
255
256 try {
257 for (int i=0; tasks!=null && i<tasks.length; i++) {
258 tasks[i].run();
259 }
260 } catch (IncompatibleVersionsException x) {
261 IllegalModificationException ix = new IllegalModificationException("Nested IncompatibleVersionsException.", x);
262 throw ix;
263 } catch (IllegalModificationException x) {
264 IllegalModificationException ix = new IllegalModificationException("Nested IllegalModificationException.", x);
265 throw ix;
266 } catch (Exception x) {
267 IllegalModificationException ix = new IllegalModificationException("Nested Exception during inner method call.", x);
268 throw ix;
269 }
270 }
271
272 protected void handleUpdate(IClientRootObject structure, String command, String content) throws IllegalModificationException {
273 if (Protocol.IDENTIFIER_FULLUPDATE.equals(command)) {
274 if (logger.isDebugEnabled())
275 logger.debug("Performing full update.\n"+content);
276
277 try {
278 ((ProtocolWorkflow)structure).__fromXML(content);
279 } catch (WorkflowFormatException x) {
280 throw new IllegalModificationException("Could not parse workflow description.", x);
281 } catch (CapacityException x) {
282 throw new IllegalModificationException("Could not parse workflow description.", x);
283 }
284 } else if (Protocol.IDENTIFIER_MODIFICATION.equals(command)) {
285 if (logger.isDebugEnabled())
286 logger.debug("Performing update.\n"+content);
287
288 Protocol.getModificationHandler().handleModification(structure, content);
289 } else {
290 throw new IllegalModificationException("Unknown update command: "+command);
291 }
292 }
293 }