View Javadoc

1   /*
2    * Copyright (c) 2005, The K-Wf Grid Consortium
3    * Fraunhofer Institute for Computer Architecture and Software Technology
4    * See http://www.kwfgrid.eu and http://www.first.fraunhofer.de for more details.
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     // FIXME: create a SwingClientWorkflow with has the runnables and exceptionholder as member.
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 	    // FIXME: This causes a deadlock if another MethodCall is nested inside this MethodCall
194 	    // (e.g. GenericProperties.put() is mapped to Property.setValue())
195 	    // FIXME!!!!
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 	    /// VERSION, COMMAND, CONTENT
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 }