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 [ModuleArbiterImpl.java]

nameclass, %method, %block, %line, %
ModuleArbiterImpl.java100% (1/1)86%  (12/14)45%  (190/421)66%  (53.5/81)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ModuleArbiterImpl100% (1/1)86%  (12/14)45%  (190/421)66%  (53.5/81)
getBlockedModules (ServiceJob): QedeqBoSet 0%   (0/1)0%   (0/32)0%   (0/9)
getName (ServiceJob): String 0%   (0/1)0%   (0/23)0%   (0/1)
unlock (ServiceJob, QedeqBo): boolean 100% (1/1)26%  (24/93)53%  (8/15)
removeLock (ServiceJob, QedeqBo): void 100% (1/1)32%  (8/25)75%  (3/4)
addLock (ServiceJob, QedeqBo): void 100% (1/1)35%  (9/26)75%  (3/4)
lock (ServiceJob, QedeqBo, Service): boolean 100% (1/1)38%  (24/64)82%  (9/11)
lockRequiredModule (InternalServiceJob, QedeqBo, Service): boolean 100% (1/1)61%  (43/71)70%  (13.9/20)
lockRequiredModule (InternalModuleServiceCall): boolean 100% (1/1)89%  (32/36)95%  (6.7/7)
<static initializer> 100% (1/1)90%  (9/10)90%  (0.9/1)
ModuleArbiterImpl (): void 100% (1/1)100% (8/8)100% (3/3)
getProcess (QedeqBo): ServiceJob 100% (1/1)100% (6/6)100% (1/1)
isAlreadyLocked (ServiceJob, QedeqBo): boolean 100% (1/1)100% (7/7)100% (1/1)
unlockRequiredModule (InternalModuleServiceCall): boolean 100% (1/1)100% (15/15)100% (3/3)
unlockRequiredModule (ServiceJob, QedeqBo): boolean 100% (1/1)100% (5/5)100% (1/1)

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.HashMap;
19import java.util.Iterator;
20import java.util.Map;
21 
22import org.qedeq.base.trace.Trace;
23import org.qedeq.base.utility.StringUtility;
24import org.qedeq.kernel.bo.common.QedeqBo;
25import org.qedeq.kernel.bo.common.QedeqBoSet;
26import org.qedeq.kernel.bo.common.ServiceJob;
27import org.qedeq.kernel.bo.job.InternalModuleServiceCallImpl;
28import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
29import org.qedeq.kernel.bo.module.InternalServiceJob;
30import org.qedeq.kernel.bo.module.ModuleArbiter;
31import org.qedeq.kernel.se.common.Service;
32import org.qedeq.kernel.se.visitor.InterruptException;
33 
34/**
35 * Get locks for modules.
36 * TODO 20130508 m31: Currently we make no difference between read and write locks. We also lock
37 * a module during the whole plugin processing for that module. This could be limited to status
38 * changes only.
39 *
40 * @author  Michael Meyling
41 */
42public class ModuleArbiterImpl implements ModuleArbiter {
43 
44    /** This class. */
45    private static final Class CLASS = ModuleArbiterImpl.class;
46 
47    /** Map blocked QEDEQ modules to service processes. */
48    private final Map blocked;
49 
50    /**
51     * Constructor.
52     */
53    public ModuleArbiterImpl() {
54        blocked = new HashMap();
55    }
56 
57    public boolean lockRequiredModule(final InternalModuleServiceCall call) throws  InterruptException {
58        call.pause();
59        call.getInternalServiceProcess().setBlocked(true);
60        try {
61            final boolean result = lockRequiredModule(call.getInternalServiceProcess(), call.getQedeq(),
62                call.getService());
63            ((InternalModuleServiceCallImpl) call).setNewlyBlockedModule(result);
64            return result;
65        } finally {
66            call.getInternalServiceProcess().setBlocked(false);
67            call.resume();
68        }
69    }
70 
71    private boolean lockRequiredModule(final InternalServiceJob process,
72            final QedeqBo qedeq, final Service service) throws  InterruptException {
73        if (isAlreadyLocked(process, qedeq)) {
74            return false;
75        }
76        process.setBlocked(true);
77        // we try to get a lock, if not we wait
78        try {
79            while (!lock(process, qedeq, service)) {
80                final Object monitor = new Object();
81                synchronized (monitor) {
82                    try {
83                        monitor.wait(1000);
84                    } catch (InterruptedException e) {
85                        process.setInterruptedState();
86                        throw new InterruptException(qedeq.getModuleAddress().createModuleContext());
87                    }
88                }
89                if (Thread.interrupted()) {
90                    process.setInterruptedState();
91                        throw new InterruptException(qedeq.getModuleAddress().createModuleContext());
92                }
93            }
94        } finally {
95            process.setBlocked(false);
96        }
97        return true;
98    }
99 
100    public boolean unlockRequiredModule(final InternalModuleServiceCall call) {
101        // TODO 20130521 m31: do it without cast
102        if (call != null && ((InternalModuleServiceCallImpl) call).getNewlyBlockedModule()) {
103            return unlockRequiredModule(call.getInternalServiceProcess(), call.getQedeq());
104        }
105        return false;
106    }
107 
108    public boolean unlockRequiredModule(final ServiceJob process, final QedeqBo qedeq) {
109        return unlock(process, qedeq);
110 
111    }
112 
113    private synchronized boolean lock(final ServiceJob process, final QedeqBo qedeq, final Service service) {
114        final String method = "lock";
115        if (Trace.isTraceOn()) {
116            Trace.info(CLASS, this, method, getName(process) + " is trying to lock " + qedeq.getName());
117        }
118        final ServiceJob origin = getProcess(qedeq);
119        if (origin != null) {
120            if (Trace.isTraceOn()) {
121                Trace.info(CLASS, this, method, getName(process) + " failed to lock " + qedeq.getName()
122                    + "\tbecause it is locked by " + getName(origin));
123            }
124            return false;
125        }
126        addLock(process, qedeq);
127        ((DefaultKernelQedeqBo) qedeq).setCurrentlyRunningService(service);
128        return true;
129    }
130 
131    private synchronized boolean unlock(final ServiceJob process, final QedeqBo qedeq) {
132        final String method = "unlock";
133        if (Trace.isTraceOn()) {
134            Trace.info(CLASS, this, method, getName(process) + " is trying to unlock " + qedeq.getName());
135        }
136        ((DefaultKernelQedeqBo) qedeq).setCurrentlyRunningService(null);
137        final ServiceJob origin = getProcess(qedeq);
138        if (origin != null) {
139            if (origin.equals(process)) {
140                removeLock(process, qedeq);
141                return true;
142            } else {
143                RuntimeException e = new IllegalArgumentException(getName(process) + " illegal unlock try for "
144                    + qedeq.getName() + " which is currently locked by service process " + getName(origin));
145                Trace.fatal(CLASS, this, method, "Programming error. Unallowed unlock try.", e);
146                // TODO 20130324 m31: later on we might handle this differently but for now:
147                throw e;
148            }
149        } else {
150            if (Trace.isTraceOn()) {
151                Trace.info(CLASS, this, method, getName(process) + " unlock unnecessary " + qedeq.getName());
152            }
153            return false;
154        }
155    }
156 
157    private String getName(final ServiceJob process) {
158        return StringUtility.format(process.getId(), 3) + " "
159            + (process.getModuleServiceCall() != null ? StringUtility.getLastDotString(
160            process.getModuleServiceCall().getService().getServiceId()) : "");
161    }
162 
163    private synchronized ServiceJob getProcess(final QedeqBo qedeq) {
164        return (ServiceJob) blocked.get(qedeq);
165    }
166 
167    private synchronized boolean isAlreadyLocked(final ServiceJob process,
168            final QedeqBo qedeq) {
169        return process.equals(blocked.get(qedeq));
170    }
171 
172    private synchronized void addLock(final ServiceJob process, final QedeqBo qedeq) {
173        if (Trace.isTraceOn()) {
174            Trace.info(CLASS, this, "addLock", getName(process) + " locked successfuly  " + qedeq.getName());
175        }
176        blocked.put(qedeq, process);
177    }
178 
179    private synchronized void removeLock(final ServiceJob process, final QedeqBo qedeq) {
180        if (Trace.isTraceOn()) {
181            Trace.info(CLASS, this, "removeLock", getName(process) + " unlocked            " + qedeq.getName());
182        }
183        blocked.remove(qedeq);
184    }
185 
186    public synchronized QedeqBoSet getBlockedModules(final ServiceJob process) {
187        QedeqBoSet result = new QedeqBoSet();
188        final Iterator i = blocked.entrySet().iterator();
189        while (i.hasNext()) {
190            final Map.Entry entry = (Map.Entry) i.next();
191            QedeqBo qedeq = (QedeqBo) entry.getKey();
192            if (process.equals(entry.getValue())) {
193                result.add(qedeq);
194            }
195        }
196        return result;
197    }
198 
199}

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