EMMA Coverage Report (generated Fri Feb 14 08:28:31 UTC 2014)
[all classes][org.qedeq.kernel.bo.service.internal]

COVERAGE SUMMARY FOR SOURCE FILE [ServiceProcessManager.java]

nameclass, %method, %block, %line, %
ServiceProcessManager.java100% (1/1)83%  (10/12)41%  (228/551)51%  (55.8/109)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ServiceProcessManager100% (1/1)83%  (10/12)41%  (228/551)51%  (55.8/109)
getRunningServiceProcesses (): ServiceJob [] 0%   (0/1)0%   (0/32)0%   (0/6)
getServiceProcesses (): ServiceJob [] 0%   (0/1)0%   (0/8)0%   (0/1)
executeService (ModuleService, ModuleServiceExecutor, QedeqBo, InternalServic... 100% (1/1)28%  (33/119)31%  (7.6/24)
executePlugin (String, KernelQedeqBo, Object, InternalServiceJob): Object 100% (1/1)28%  (60/212)38%  (14.6/38)
createServiceJob (String): InternalServiceJob 100% (1/1)29%  (12/41)43%  (3/7)
createServiceCall (Service, QedeqBo, Parameters, Parameters, InternalServiceJ... 100% (1/1)73%  (40/55)80%  (8.8/11)
<static initializer> 100% (1/1)90%  (9/10)90%  (0.9/1)
ServiceProcessManager (PluginManager, ModuleArbiter): void 100% (1/1)100% (24/24)100% (7/7)
createServiceProcess (String): InternalServiceJobImpl 100% (1/1)100% (14/14)100% (3/3)
endServiceCall (InternalModuleServiceCall): void 100% (1/1)100% (6/6)100% (2/2)
terminateAllServiceProcesses (): void 100% (1/1)100% (18/18)100% (4/4)
terminateAndRemoveAllServiceProcesses (): void 100% (1/1)100% (12/12)100% (5/5)

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 
16package org.qedeq.kernel.bo.service.internal;
17 
18import java.util.ArrayList;
19import java.util.List;
20 
21import org.qedeq.base.io.Parameters;
22import org.qedeq.base.trace.Trace;
23import org.qedeq.kernel.bo.KernelContext;
24import org.qedeq.kernel.bo.common.ModuleServiceResult;
25import org.qedeq.kernel.bo.common.QedeqBo;
26import org.qedeq.kernel.bo.common.ServiceJob;
27import org.qedeq.kernel.bo.job.InternalModuleServiceCallImpl;
28import org.qedeq.kernel.bo.job.InternalServiceJobImpl;
29import org.qedeq.kernel.bo.log.QedeqLog;
30import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
31import org.qedeq.kernel.bo.module.InternalServiceJob;
32import org.qedeq.kernel.bo.module.KernelQedeqBo;
33import org.qedeq.kernel.bo.module.ModuleArbiter;
34import org.qedeq.kernel.bo.service.basis.ModuleServiceExecutor;
35import org.qedeq.kernel.bo.service.basis.ModuleServicePlugin;
36import org.qedeq.kernel.bo.service.basis.ModuleServicePluginExecutor;
37import org.qedeq.kernel.se.common.ModuleService;
38import org.qedeq.kernel.se.common.Service;
39import org.qedeq.kernel.se.visitor.InterruptException;
40 
41/**
42 * Manage all known processes.
43 */
44public 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    public ServiceProcessManager(final PluginManager pluginManager, final ModuleArbiter arbiter) {
71        this.pluginManager = pluginManager;
72        this.arbiter = arbiter;
73    }
74 
75 
76    /**
77     * Get all service processes.
78     *
79     * @return  All service processes.
80     */
81    public synchronized ServiceJob[] getServiceProcesses() {
82        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    public synchronized ServiceJob[] getRunningServiceProcesses() {
92        final ArrayList result = new ArrayList(processes);
93        for (int i = 0; i < result.size(); ) {
94            if (!((ServiceJob) result.get(i)).isRunning()) {
95                result.remove(i);
96            } else {
97                i++;
98            }
99        }
100        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    public InternalModuleServiceCallImpl createServiceCall(final Service service,
115            final QedeqBo qedeq, final Parameters configParameters, final Parameters parameters,
116            final InternalServiceJob process) throws InterruptException {
117        if (!process.isRunning()) { // should not occur
118            throw new RuntimeException("Service process is not running any more.");
119        }
120        if (!process.getThread().isAlive()) {
121            throw new RuntimeException("thread is already dead");
122        }
123        final InternalModuleServiceCallImpl call = new InternalModuleServiceCallImpl(service, qedeq, configParameters,
124            parameters, process, process.getModuleServiceCall());
125        synchronized (this) {
126            calls.add(call);
127        }
128        process.setInternalServiceCall(call);
129        arbiter.lockRequiredModule(call);
130        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    public void endServiceCall(final InternalModuleServiceCall call) {
139        arbiter.unlockRequiredModule(call);
140    }
141 
142    /**
143     * Remove all service processes. All processes are also terminated via interruption.
144     */
145    public synchronized void terminateAndRemoveAllServiceProcesses() {
146        terminateAllServiceProcesses();
147        processes.clear();
148        finished.clear();
149        calls.clear();
150    }
151 
152    /**
153     * Terminate all service processes.
154     */
155    public synchronized void terminateAllServiceProcesses() {
156        for (int i = 0; i < processes.size(); i++) {
157            final ServiceJob proc = (ServiceJob) processes.get(i);
158            proc.interrupt();
159        }
160    }
161 
162    public synchronized InternalServiceJobImpl createServiceProcess(final String action) {
163        final InternalServiceJobImpl process = new InternalServiceJobImpl(arbiter, action);
164        processes.add(process);
165        return process;
166    }
167 
168    public ModuleServiceResult executeService(final ModuleService service, final ModuleServiceExecutor executor,
169            final QedeqBo qedeq, final InternalServiceJob process) throws InterruptException {
170        final String method = "executePlugin(String, KernelQedeqBo, Object)";
171        if (process == null) {
172            throw new NullPointerException("ServiceProcess must not be null");
173        }
174        final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(service);
175        InternalModuleServiceCallImpl call = null;
176        try {
177            call = createServiceCall(service, qedeq, configParameters, Parameters.EMPTY, process);
178            executor.executeService(call);
179            return call.getServiceResult();
180        } catch (final RuntimeException e) {
181            final String msg = service.getServiceAction() + " failed with a runtime exception.";
182            Trace.fatal(CLASS, this, method, msg, e);
183            QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
184            if (call != null) {
185                call.finishError(msg + " " + e.getMessage());
186            }
187            process.setFailureState();
188            return call != null ? call.getServiceResult() : null;
189        } catch (final InterruptException e) {
190            final String msg = service.getServiceAction() + " was canceled by user.";
191            QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
192            if (call != null) {
193                call.interrupt();
194            }
195            process.setInterruptedState();
196            throw e;
197        } finally {
198            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    public Object executePlugin(final String id, final KernelQedeqBo qedeq, final Object data,
214            final InternalServiceJob process) throws InterruptException {
215        final String method = "executePlugin(String, KernelQedeqBo, Object, InternalServiceJob)";
216        final ModuleServicePlugin plugin = pluginManager.getPlugin(id);
217        if (plugin == null) {
218            final String message = "Kernel does not know about plugin: ";
219            final RuntimeException e = new RuntimeException(message + id);
220            Trace.fatal(CLASS, this, method, message + id,
221                e);
222            throw e;
223        }
224        final Parameters configParameters = KernelContext.getInstance().getConfig().getServiceEntries(plugin);
225        if (!process.isRunning()) {
226            // TODO 20140124 m31: but if it was interrupted we want to throw a InterrruptException
227            final String message = "Process " + process.getId() + " was already finished: "
228                + process.getExecutionActionDescription();
229            final RuntimeException e = new RuntimeException(message + id);
230            Trace.fatal(CLASS, this, method, message + id,
231                e);
232            throw e;
233        }
234        InternalModuleServiceCallImpl call = null;
235        try {
236            call = createServiceCall(plugin, qedeq, configParameters, Parameters.EMPTY,
237                process);
238            final ModuleServicePluginExecutor exe = plugin.createExecutor(qedeq, configParameters);
239            call.setServiceCompleteness(exe);
240            final Object result = exe.executePlugin(call, data);
241            if (exe.getInterrupted()) {
242                call.interrupt();
243                throw new InterruptException(qedeq.getModuleAddress().createModuleContext());
244            } else {
245                call.finishOk();
246                process.setInternalServiceCall((InternalModuleServiceCall) call.getParentServiceCall());
247            }
248            return result;
249        } catch (final RuntimeException e) {
250            final String msg = plugin.getServiceAction() + " failed with a runtime exception.";
251            Trace.fatal(CLASS, this, method, msg, e);
252            QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
253            if (call != null) {
254                call.finishError(msg + ": " + e.getMessage());
255            }
256            return null;
257        } catch (final InterruptException e) {
258            final String msg = plugin.getServiceAction() + " was canceled by user.";
259            QedeqLog.getInstance().logFailureReply(msg, qedeq.getUrl(), e.getMessage());
260            if (call != null) {
261                call.interrupt();
262            }
263            throw e;
264        } finally {
265            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    public InternalServiceJob createServiceJob(final String id) {
277        final ModuleServicePlugin plugin = pluginManager.getPlugin(id);
278        if (plugin == null) {
279            final String message = "Kernel does not know about plugin: ";
280            final RuntimeException e = new RuntimeException(message + id);
281            Trace.fatal(CLASS, this, "createServiceJob", message + id, e);
282            throw e;
283        }
284        return createServiceProcess(plugin.getServiceAction());
285    }
286 
287}

[all classes][org.qedeq.kernel.bo.service.internal]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov