Clover Coverage Report
Coverage timestamp: Fri May 24 2013 13:47:27 UTC
../../../../../../img/srcFileCovDistChart6.png 80% of files have more coverage
104   290   35   8.67
36   192   0.34   12
12     2.92  
1    
 
  ServiceProcessManager       Line # 39 104 35 57.9% 0.57894737
 
  (97)
 
1    /* This file is part of the project "Hilbert II" - http://www.qedeq.org
2    *
3    * Copyright 2000-2013, Michael Meyling <mime@qedeq.org>.
4    *
5    * "Hilbert II" is free software; you can redistribute
6    * it and/or modify it under the terms of the GNU General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10    * This program is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    * GNU General Public License for more details.
14    */
15   
16    package org.qedeq.kernel.bo.service.control;
17   
18    import java.util.ArrayList;
19    import java.util.List;
20   
21    import org.qedeq.base.io.Parameters;
22    import org.qedeq.base.trace.Trace;
23    import org.qedeq.kernel.bo.KernelContext;
24    import org.qedeq.kernel.bo.common.ServiceProcess;
25    import org.qedeq.kernel.bo.common.ServiceResult;
26    import org.qedeq.kernel.bo.log.QedeqLog;
27    import org.qedeq.kernel.bo.module.InternalServiceCall;
28    import org.qedeq.kernel.bo.module.InternalServiceProcess;
29    import org.qedeq.kernel.bo.module.KernelQedeqBo;
30    import org.qedeq.kernel.bo.module.PluginBo;
31    import org.qedeq.kernel.bo.module.PluginExecutor;
32    import org.qedeq.kernel.bo.module.ServiceExecutor;
33    import org.qedeq.kernel.se.common.Service;
34    import org.qedeq.kernel.se.visitor.InterruptException;
35   
36    /**
37    * Manage all known processes.
38    */
 
39    public class ServiceProcessManager {
40   
41    /** This class. */
42    private static final Class CLASS = ServiceProcessManager.class;
43   
44    /** Stores all running processes. */
45    private final List processes = new ArrayList();
46   
47    /** Stores some finished processes. FIXME 20130408 m31: use! */
48    private final List finished = new ArrayList();
49   
50    /** Stores all calls. */
51    private final List calls = new ArrayList();
52   
53    /** Manage all known plugins. */
54    private final PluginManager pluginManager;
55   
56    /** Manage synchronized module access. */
57    private final ModuleArbiter arbiter;
58   
59    /**
60    * Constructor.
61    *
62    * @param pluginManager Collects process information.
63    * @param arbiter For module access synchronization.
64    */
 
65  471 toggle public ServiceProcessManager(final PluginManager pluginManager, final ModuleArbiter arbiter) {
66  471 this.pluginManager = pluginManager;
67  471 this.arbiter = arbiter;
68    }
69   
70   
71    /**
72    * Get all service processes.
73    *
74    * @return All service processes.
75    */
 
76  0 toggle public synchronized ServiceProcess[] getServiceProcesses() {
77  0 return (ServiceProcess[]) processes.toArray(new ServiceProcess[] {});
78    }
79   
80    /**
81    * Get all running service processes. But remember a running process might currently
82    * be blocked.
83    *
84    * @return All service running processes.
85    */
 
86  0 toggle public synchronized ServiceProcess[] getRunningServiceProcesses() {
87  0 final ArrayList result = new ArrayList(processes);
88  0 for (int i = 0; i < result.size(); ) {
89  0 if (!((ServiceProcess) result.get(i)).isRunning()) {
90  0 result.remove(i);
91    } else {
92  0 i++;
93    }
94    }
95  0 return (ServiceProcess[]) result.toArray(new ServiceProcess[] {});
96    }
97   
98    /**
99    * Create service process. Might block further execution, because an exclusive access to given module is given.
100    *
101    * @param service The service that runs in current thread.
102    * @param qedeq QEDEQ module for service.
103    * @param configParameters Config parameters for the service.
104    * @param parameters Parameter for this service call.
105    * @param process We run in this process.
106    * @return Created service call. Never <code>null</code> (if no {@link InterruptException} occurred).
107    * @throws InterruptException User canceled call.
108    */
 
109  2170 toggle public ServiceCallImpl createServiceCall(final Service service,
110    final KernelQedeqBo qedeq, final Parameters configParameters, final Parameters parameters,
111    final InternalServiceProcess process) throws InterruptException {
112  2170 if (!process.isRunning()) { // should not occur
113  0 throw new RuntimeException("Service process is not running any more.");
114    }
115  2170 if (!process.getThread().isAlive()) {
116  0 throw new RuntimeException("thread is already dead");
117    }
118  2170 final ServiceCallImpl call = new ServiceCallImpl(service, qedeq, configParameters, parameters, process,
119    process.getServiceCall());
120  2170 synchronized (this) {
121  2170 calls.add(call);
122    }
123  2170 process.setInternalServiceCall(call);
124  2170 lockRequiredModule(call, qedeq, service);
125  2170 return call;
126    }
127   
128    /**
129    * End service call by unlocking previously locked module.
130    *
131    * @param call End this call, which should be finished, interrupted or halted before.
132    */
 
133  2185 toggle public void endServiceCall(final InternalServiceCall call) {
134  2185 if (call != null && ((ServiceCallImpl) call).getNewlyBlockedModule()) { // TODO 20130521 m31: do it without cast
135  2051 unlockRequiredModule(call, call.getKernelQedeq());
136    }
137    }
138   
139    /**
140    * Remove all service processes. All processes are also terminated via interruption.
141    */
 
142  471 toggle public synchronized void terminateAndRemoveAllServiceProcesses() {
143  471 terminateAllServiceProcesses();
144  471 processes.clear();
145  471 finished.clear();
146  471 calls.clear();
147    }
148   
149    /**
150    * Terminate all service processes.
151    */
 
152  471 toggle public synchronized void terminateAllServiceProcesses() {
153  1482 for (int i = 0; i < processes.size(); i++) {
154  1011 final ServiceProcess proc = (ServiceProcess) processes.get(i);
155  1011 proc.interrupt();
156    }
157    }
158   
 
159  1011 toggle public synchronized ServiceProcessImpl createServiceProcess(final String action) {
160  1011 final ServiceProcessImpl process = new ServiceProcessImpl(arbiter, action);
161  1011 processes.add(process);
162  1011 return process;
163    }
164   
 
165  658 toggle ServiceResult executeService(final Service service, final ServiceExecutor executor, final KernelQedeqBo qedeq,
166    final InternalServiceProcess process) throws InterruptException {
167  658 final String method = "executePlugin(String, KernelQedeqBo, Object)";
168  658 if (process == null) {
169  0 throw new NullPointerException("ServiceProcess must not be null");
170    }
171  658 final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(service);
172  658 ServiceCallImpl call = null;
173  658 try {
174  658 call = createServiceCall(service, qedeq, configParameters, Parameters.EMPTY, process);
175  658 executor.executeService(call);
176  658 return call.getServiceResult();
177    } catch (final RuntimeException e) {
178  0 final String msg = service.getServiceAction() + " failed with a runtime exception.";
179  0 Trace.fatal(CLASS, this, method, msg, e);
180  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
181  0 if (call != null) {
182  0 call.finish(msg + " " + e.getMessage());
183    }
184  0 process.setFailureState();
185  0 return call != null ? call.getServiceResult() : null;
186    } catch (final InterruptException e) {
187  0 final String msg = service.getServiceAction() + " was canceled by user.";
188  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
189  0 if (call != null) {
190  0 call.interrupt();
191    }
192  0 process.setFailureState();
193  0 throw e;
194    } finally {
195  658 endServiceCall(call);
196    }
197    }
198   
199    /**
200    * Execute a plugin on an QEDEQ module.
201    *
202    * @param id Plugin to use.
203    * @param qedeq QEDEQ module to work on.
204    * @param data Process parameters.
205    * @param proc Process. Might be <code>null</code>.
206    * @return Plugin specific result object. Might be <code>null</code>.
207    * @throws InterruptException User interrupt occured.
208    * @throws RuntimeException Plugin unknown.
209    */
 
210  1293 toggle Object executePlugin(final String id, final KernelQedeqBo qedeq, final Object data,
211    final InternalServiceProcess proc) throws InterruptException {
212  1293 final String method = "executePlugin(String, KernelQedeqBo, Object)";
213  1293 final PluginBo plugin = pluginManager.getPlugin(id);
214  1293 if (plugin == null) {
215  0 final String message = "Kernel does not know about plugin: ";
216  0 final RuntimeException e = new RuntimeException(message + id);
217  0 Trace.fatal(CLASS, this, method, message + id,
218    e);
219  0 throw e;
220    }
221  1293 final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(plugin);
222  1293 InternalServiceProcess process = null;
223  1293 if (proc != null) {
224  1021 if (!proc.isRunning()) {
225  0 return null;
226    }
227  1021 process = proc;
228    } else {
229  272 process = createServiceProcess(plugin.getServiceAction());
230    }
231  1293 ServiceCallImpl call = null;
232  1293 try {
233  1293 call = createServiceCall(plugin, qedeq, configParameters, Parameters.EMPTY,
234    process);
235  1293 final PluginExecutor exe = plugin.createExecutor(qedeq, configParameters);
236  1293 call.setServiceCompleteness(exe);
237  1293 final Object result = exe.executePlugin(call, data);
238  1293 if (exe.getInterrupted()) {
239  0 call.interrupt();
240  0 throw new InterruptException(qedeq.getModuleAddress().createModuleContext());
241    } else {
242  1293 call.finish();
243  1293 process.setInternalServiceCall((InternalServiceCall) call.getParentServiceCall());
244    }
245  1293 return result;
246    } catch (final RuntimeException e) {
247  0 final String msg = plugin.getServiceAction() + " failed with a runtime exception.";
248  0 Trace.fatal(CLASS, this, method, msg, e);
249  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
250  0 if (call != null) {
251  0 call.finish(msg + ": " + e.getMessage());
252    }
253  0 return null;
254    } catch (final InterruptException e) {
255  0 final String msg = plugin.getServiceAction() + " was canceled by user.";
256  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
257  0 if (call != null) {
258  0 call.interrupt();
259    }
260  0 throw e;
261    } finally {
262  1293 endServiceCall(call);
263    // if we created the process we also close it
264  1293 if (proc == null) {
265  272 if (process.isRunning()) {
266  272 process.setSuccessState();
267    }
268    }
269    }
270    }
271   
 
272  2170 toggle public boolean lockRequiredModule(final ServiceCallImpl call, final KernelQedeqBo qedeq, final Service service)
273    throws InterruptException {
274  2170 call.pause();
275  2170 call.getInternalServiceProcess().setBlocked(true);
276  2170 try {
277  2170 final boolean result = arbiter.lockRequiredModule(call.getInternalServiceProcess(), qedeq, service);
278  2170 call.setNewlyBlockedModule(result);
279  2170 return result;
280    } finally {
281  2170 call.getInternalServiceProcess().setBlocked(false);
282  2170 call.resume();
283    }
284    }
285   
 
286  2051 toggle public boolean unlockRequiredModule(final InternalServiceCall call, final KernelQedeqBo qedeq) {
287  2051 return arbiter.unlockRequiredModule(call.getInternalServiceProcess(), qedeq);
288    }
289   
290    }