ModuleArbiter.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2013,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.kernel.bo.service;
017 
018 import java.util.HashMap;
019 import java.util.Map;
020 
021 import org.qedeq.base.utility.StringUtility;
022 import org.qedeq.kernel.bo.common.ServiceProcess;
023 import org.qedeq.kernel.bo.module.InternalServiceProcess;
024 import org.qedeq.kernel.bo.module.KernelQedeqBo;
025 import org.qedeq.kernel.se.common.ModuleContext;
026 import org.qedeq.kernel.se.visitor.InterruptException;
027 
028 /**
029  * Get locks for modules.
030  *
031  @author  Michael Meyling
032  */
033 public class ModuleArbiter {
034 
035     /** Map blocked QEDEQ modules to service processes. */
036     private final Map blocked;
037 
038     /**
039      * Constructor.
040      */
041     public ModuleArbiter() {
042         blocked = new HashMap();
043     }
044 
045     /**
046      * Lock QEDEQ module.
047      *
048      @param   process This process acquires the lock.
049      @param   qedeq   Lock this module.
050      @return  The process locked this module already, we didn't do anything.
051      @throws  InterruptException  Lock acquirement interrupted.
052      */
053     public boolean lockRequiredModule(final InternalServiceProcess process,
054             final KernelQedeqBo qedeqthrows  InterruptException {
055         if (isAlreadyLocked(process, qedeq)) {
056             return false;
057         }
058         while (!lock(process, qedeq)) {
059             final Object monitor = new Object();
060             synchronized (monitor) {
061                 try {
062                     monitor.wait(10000);
063                 catch (InterruptedException e) {
064                     process.setFailureState();
065                     throw new InterruptException(new ModuleContext(qedeq.getModuleAddress()));
066                 }
067             }
068             if (Thread.interrupted()) {
069                 process.setFailureState();
070                     throw new InterruptException(new ModuleContext(qedeq.getModuleAddress()));
071             }
072         }
073         return true;
074     }
075 
076     private synchronized boolean lock(final ServiceProcess process, final KernelQedeqBo qedeq) {
077         System.out.println(getName(process" is trying to lock   " + qedeq.getName());
078         final ServiceProcess origin = (ServiceProcessblocked.get(qedeq);
079         if (origin != null) {
080             System.out.println(getName(process" failed to lock      " + qedeq.getName());
081             System.out.println("\tbecause it is locked by " + getName(origin));
082             return false;
083         }
084         System.out.println(getName(process" locked successfuly  " + qedeq.getName());
085         blocked.put(qedeq, process);
086         return true;
087     }
088 
089     private String getName(final ServiceProcess process) {
090         return StringUtility.format(process.getId()3" "
091             (process.getPluginCall() != null ? StringUtility.getLastDotString(
092             process.getPluginCall().getPlugin().getPluginId()) "");
093     }
094 
095     /**
096      * Unlock module again.
097      *
098      @param   process     This process must have acquired the lock.
099      @param   qedeq       This module was locked before.
100      */
101     public void unlockRequiredModule(final ServiceProcess process, final KernelQedeqBo qedeq) {
102         unlock(process, qedeq);
103     }
104 
105     private synchronized void unlock(final ServiceProcess process, final KernelQedeqBo qedeq) {
106         System.out.println(getName(process" is trying to unlock " + qedeq.getName());
107         final ServiceProcess origin = (ServiceProcessblocked.get(qedeq);
108         if (origin != null) {
109             if (origin.equals(process)) {
110                 System.out.println(getName(process" unlocked            " + qedeq.getName());
111                 blocked.remove(qedeq);
112             else {
113                 System.out.println(getName(process" illegal unlock try  " + qedeq.getName());
114                 // FIXME 20130324 m31: later on we might handle this differently but for now:
115                 throw new IllegalArgumentException("locked by service process " + origin.getId());
116             }
117         else {
118             System.out.println(getName(process" unlock unneccassary " + qedeq.getName());
119         }
120     }
121 
122     private synchronized ServiceProcess getProcess(final KernelQedeqBo qedeq) {
123         return (ServiceProcessblocked.get(qedeq);
124     }
125 
126     private synchronized boolean isLocked(final KernelQedeqBo qedeq) {
127         return blocked.containsKey(qedeq);
128     }
129 
130     private synchronized boolean isAlreadyLocked(final ServiceProcess process,
131             final KernelQedeqBo qedeq) {
132         return process.equals(blocked.get(qedeq));
133     }
134 
135     private synchronized void addLock(final ServiceProcess process, final KernelQedeqBo qedeq) {
136         blocked.put(qedeq, process);
137     }
138 
139     private synchronized void removeLock(final KernelQedeqBo qedeq) {
140         blocked.remove(qedeq);
141     }
142 
143 }