Clover Coverage Report
Coverage timestamp: Fri Feb 14 2014 07:28:57 UTC
../../../../../../img/srcFileCovDistChart5.png 86% of files have more coverage
97   287   30   8.82
30   183   0.31   11
11     2.73  
1    
 
  ServiceProcessManager       Line # 44 97 30 48.6% 0.48550725
 
  (112)
 
1    /* This file is part of the project "Hilbert II" - http://www.qedeq.org
2    *
3    * Copyright 2000-2014, 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.internal;
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.ModuleServiceResult;
25    import org.qedeq.kernel.bo.common.QedeqBo;
26    import org.qedeq.kernel.bo.common.ServiceJob;
27    import org.qedeq.kernel.bo.job.InternalModuleServiceCallImpl;
28    import org.qedeq.kernel.bo.job.InternalServiceJobImpl;
29    import org.qedeq.kernel.bo.log.QedeqLog;
30    import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
31    import org.qedeq.kernel.bo.module.InternalServiceJob;
32    import org.qedeq.kernel.bo.module.KernelQedeqBo;
33    import org.qedeq.kernel.bo.module.ModuleArbiter;
34    import org.qedeq.kernel.bo.service.basis.ModuleServiceExecutor;
35    import org.qedeq.kernel.bo.service.basis.ModuleServicePlugin;
36    import org.qedeq.kernel.bo.service.basis.ModuleServicePluginExecutor;
37    import org.qedeq.kernel.se.common.ModuleService;
38    import org.qedeq.kernel.se.common.Service;
39    import org.qedeq.kernel.se.visitor.InterruptException;
40   
41    /**
42    * Manage all known processes.
43    */
 
44    public class ServiceProcessManager {
45   
46    /** This class. */
47    private static final Class CLASS = ServiceProcessManager.class;
48   
49    /** Stores all running processes. */
50    private final List processes = new ArrayList();
51   
52    /** Stores some finished processes. FIXME 20130408 m31: use! */
53    private final List finished = new ArrayList();
54   
55    /** Stores all calls. */
56    private final List calls = new ArrayList();
57   
58    /** Manage all known plugins. */
59    private final PluginManager pluginManager;
60   
61    /** Manage synchronized module access. */
62    private final ModuleArbiter arbiter;
63   
64    /**
65    * Constructor.
66    *
67    * @param pluginManager Collects process information.
68    * @param arbiter For module access synchronization.
69    */
 
70  488 toggle public ServiceProcessManager(final PluginManager pluginManager, final ModuleArbiter arbiter) {
71  488 this.pluginManager = pluginManager;
72  488 this.arbiter = arbiter;
73    }
74   
75   
76    /**
77    * Get all service processes.
78    *
79    * @return All service processes.
80    */
 
81  0 toggle public synchronized ServiceJob[] getServiceProcesses() {
82  0 return (ServiceJob[]) processes.toArray(new ServiceJob[] {});
83    }
84   
85    /**
86    * Get all running service processes. But remember a running process might currently
87    * be blocked.
88    *
89    * @return All service running processes.
90    */
 
91  0 toggle public synchronized ServiceJob[] getRunningServiceProcesses() {
92  0 final ArrayList result = new ArrayList(processes);
93  0 for (int i = 0; i < result.size(); ) {
94  0 if (!((ServiceJob) result.get(i)).isRunning()) {
95  0 result.remove(i);
96    } else {
97  0 i++;
98    }
99    }
100  0 return (ServiceJob[]) result.toArray(new ServiceJob[] {});
101    }
102   
103    /**
104    * Create service call. Might block further execution, because an exclusive access to given module is given.
105    *
106    * @param service The service that runs in current thread.
107    * @param qedeq QEDEQ module for service.
108    * @param configParameters Config parameters for the service.
109    * @param parameters Parameter for this service call.
110    * @param process We run in this process.
111    * @return Created service call. Never <code>null</code> (if no {@link InterruptException} occurred).
112    * @throws InterruptException User canceled call.
113    */
 
114  1589 toggle public InternalModuleServiceCallImpl createServiceCall(final Service service,
115    final QedeqBo qedeq, final Parameters configParameters, final Parameters parameters,
116    final InternalServiceJob process) throws InterruptException {
117  1589 if (!process.isRunning()) { // should not occur
118  0 throw new RuntimeException("Service process is not running any more.");
119    }
120  1589 if (!process.getThread().isAlive()) {
121  0 throw new RuntimeException("thread is already dead");
122    }
123  1589 final InternalModuleServiceCallImpl call = new InternalModuleServiceCallImpl(service, qedeq, configParameters,
124    parameters, process, process.getModuleServiceCall());
125  1589 synchronized (this) {
126  1589 calls.add(call);
127    }
128  1589 process.setInternalServiceCall(call);
129  1589 arbiter.lockRequiredModule(call);
130  1589 return call;
131    }
132   
133    /**
134    * End service call by unlocking previously locked module.
135    *
136    * @param call End this call, which should be finished, interrupted or halted before.
137    */
 
138  1741 toggle public void endServiceCall(final InternalModuleServiceCall call) {
139  1741 arbiter.unlockRequiredModule(call);
140    }
141   
142    /**
143    * Remove all service processes. All processes are also terminated via interruption.
144    */
 
145  488 toggle public synchronized void terminateAndRemoveAllServiceProcesses() {
146  488 terminateAllServiceProcesses();
147  488 processes.clear();
148  488 finished.clear();
149  488 calls.clear();
150    }
151   
152    /**
153    * Terminate all service processes.
154    */
 
155  488 toggle public synchronized void terminateAllServiceProcesses() {
156  1339 for (int i = 0; i < processes.size(); i++) {
157  851 final ServiceJob proc = (ServiceJob) processes.get(i);
158  851 proc.interrupt();
159    }
160    }
161   
 
162  851 toggle public synchronized InternalServiceJobImpl createServiceProcess(final String action) {
163  851 final InternalServiceJobImpl process = new InternalServiceJobImpl(arbiter, action);
164  851 processes.add(process);
165  851 return process;
166    }
167   
 
168  463 toggle public ModuleServiceResult executeService(final ModuleService service, final ModuleServiceExecutor executor,
169    final QedeqBo qedeq, final InternalServiceJob process) throws InterruptException {
170  463 final String method = "executePlugin(String, KernelQedeqBo, Object)";
171  463 if (process == null) {
172  0 throw new NullPointerException("ServiceProcess must not be null");
173    }
174  463 final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(service);
175  463 InternalModuleServiceCallImpl call = null;
176  463 try {
177  463 call = createServiceCall(service, qedeq, configParameters, Parameters.EMPTY, process);
178  463 executor.executeService(call);
179  463 return call.getServiceResult();
180    } catch (final RuntimeException e) {
181  0 final String msg = service.getServiceAction() + " failed with a runtime exception.";
182  0 Trace.fatal(CLASS, this, method, msg, e);
183  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
184  0 if (call != null) {
185  0 call.finishError(msg + " " + e.getMessage());
186    }
187  0 process.setFailureState();
188  0 return call != null ? call.getServiceResult() : null;
189    } catch (final InterruptException e) {
190  0 final String msg = service.getServiceAction() + " was canceled by user.";
191  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
192  0 if (call != null) {
193  0 call.interrupt();
194    }
195  0 process.setInterruptedState();
196  0 throw e;
197    } finally {
198  463 endServiceCall(call);
199    }
200    }
201   
202    /**
203    * Execute a plugin on an QEDEQ module.
204    *
205    * @param id Plugin to use.
206    * @param qedeq QEDEQ module to work on.
207    * @param data Process parameters.
208    * @param process Process. Must not be <code>null</code>..
209    * @return Plugin Specific result object. Might be <code>null</code>.
210    * @throws InterruptException User interrupt occurred.
211    * @throws RuntimeException Plugin unknown or process is not running any more.
212    */
 
213  1126 toggle public Object executePlugin(final String id, final KernelQedeqBo qedeq, final Object data,
214    final InternalServiceJob process) throws InterruptException {
215  1126 final String method = "executePlugin(String, KernelQedeqBo, Object, InternalServiceJob)";
216  1126 final ModuleServicePlugin plugin = pluginManager.getPlugin(id);
217  1126 if (plugin == null) {
218  0 final String message = "Kernel does not know about plugin: ";
219  0 final RuntimeException e = new RuntimeException(message + id);
220  0 Trace.fatal(CLASS, this, method, message + id,
221    e);
222  0 throw e;
223    }
224  1126 final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(plugin);
225  1126 if (!process.isRunning()) {
226    // TODO 20140124 m31: but if it was interrupted we want to throw a InterrruptException
227  0 final String message = "Process " + process.getId() + " was already finished: "
228    + process.getExecutionActionDescription();
229  0 final RuntimeException e = new RuntimeException(message + id);
230  0 Trace.fatal(CLASS, this, method, message + id,
231    e);
232  0 throw e;
233    }
234  1126 InternalModuleServiceCallImpl call = null;
235  1126 try {
236  1126 call = createServiceCall(plugin, qedeq, configParameters, Parameters.EMPTY,
237    process);
238  1126 final ModuleServicePluginExecutor exe = plugin.createExecutor(qedeq, configParameters);
239  1126 call.setServiceCompleteness(exe);
240  1126 final Object result = exe.executePlugin(call, data);
241  1126 if (exe.getInterrupted()) {
242  0 call.interrupt();
243  0 throw new InterruptException(qedeq.getModuleAddress().createModuleContext());
244    } else {
245  1126 call.finishOk();
246  1126 process.setInternalServiceCall((InternalModuleServiceCall) call.getParentServiceCall());
247    }
248  1126 return result;
249    } catch (final RuntimeException e) {
250  0 final String msg = plugin.getServiceAction() + " failed with a runtime exception.";
251  0 Trace.fatal(CLASS, this, method, msg, e);
252  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
253  0 if (call != null) {
254  0 call.finishError(msg + ": " + e.getMessage());
255    }
256  0 return null;
257    } catch (final InterruptException e) {
258  0 final String msg = plugin.getServiceAction() + " was canceled by user.";
259  0 QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
260  0 if (call != null) {
261  0 call.interrupt();
262    }
263  0 throw e;
264    } finally {
265  1126 endServiceCall(call);
266    }
267    }
268   
269    /**
270    * Create a service job for executing a plugin.
271    *
272    * @param id Plugin to use.
273    * @return Process.
274    * @throws RuntimeException Plugin unknown.
275    */
 
276  320 toggle public InternalServiceJob createServiceJob(final String id) {
277  320 final ModuleServicePlugin plugin = pluginManager.getPlugin(id);
278  320 if (plugin == null) {
279  0 final String message = "Kernel does not know about plugin: ";
280  0 final RuntimeException e = new RuntimeException(message + id);
281  0 Trace.fatal(CLASS, this, "createServiceJob", message + id, e);
282  0 throw e;
283    }
284  320 return createServiceProcess(plugin.getServiceAction());
285    }
286   
287    }