KernelQedeqBoStorage.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2014,  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.internal;
017 
018 import java.util.ArrayList;
019 import java.util.HashMap;
020 import java.util.Iterator;
021 import java.util.List;
022 import java.util.Map;
023 
024 import org.apache.commons.lang.StringUtils;
025 import org.qedeq.base.trace.Trace;
026 import org.qedeq.kernel.bo.KernelContext;
027 import org.qedeq.kernel.bo.common.QedeqBo;
028 import org.qedeq.kernel.bo.log.QedeqLog;
029 import org.qedeq.kernel.bo.module.InternalKernelServices;
030 import org.qedeq.kernel.bo.module.KernelModuleReferenceList;
031 import org.qedeq.kernel.bo.module.KernelQedeqBo;
032 import org.qedeq.kernel.se.common.ModuleAddress;
033 import org.qedeq.kernel.se.state.LoadingState;
034 
035 /**
036  * Holds all known QEDEQ modules. Doesn't now anything about locking.
037  */
038 class KernelQedeqBoStorage {
039 
040     /** This class. */
041     private static final Class CLASS = KernelQedeqBoStorage.class;
042 
043     /** QEDEQ Modules; key: ModuleAddress, value: KernelQedeqBo. */
044     private final Map bos = new HashMap();
045 
046 
047     /**
048      * Get {@link DefaultKernelQedeqBo} for an module address. If it is unknown it will be created.
049      *
050      @param   services    Internal kernel services.
051      @param   address     Module address.
052      @return  QedeqBo for module.
053      */
054     synchronized DefaultKernelQedeqBo getKernelQedeqBo(final InternalKernelServices services,
055             final ModuleAddress address) {
056         if (bos.containsKey(address)) {
057             return (DefaultKernelQedeqBobos.get(address);
058         }
059         final DefaultKernelQedeqBo prop = new DefaultKernelQedeqBo(services, address);
060         bos.put(address, prop);
061         return prop;
062     }
063 
064     /**
065      * Remove all modules from memory.
066      */
067     synchronized void removeAllModules() {
068         final String method = "removeAllModules()";
069         Trace.begin(CLASS, this, method);
070         try {
071             for (final Iterator iterator
072                     = bos.entrySet().iterator();
073                     iterator.hasNext()) {
074                 Map.Entry entry = (Map.Entryiterator.next();
075                 final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBoentry.getValue();
076                 prop.delete();
077             }
078             bos.clear();
079         catch (RuntimeException e) {
080             Trace.trace(CLASS, this, method, e);
081         finally {
082             Trace.end(CLASS, this, method);
083         }
084     }
085 
086     /**
087      * Validate module dependencies and throw Error if they are not correct.
088      */
089     synchronized void validateDependencies() {
090         final String method = "validateDependencies";
091         String url = StringUtils.EMPTY;
092         String text = StringUtils.EMPTY;
093         boolean error = false;
094         Trace.begin(CLASS, this, method);
095 // for debugging: print dependency tree:
096 //        for (final Iterator iterator = bos.entrySet().iterator(); iterator.hasNext(); ) {
097 //            Map.Entry entry = (Map.Entry) iterator.next();
098 //            final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBo) entry.getValue();
099 //            prop.getStateManager().printDependencyTree();
100 //        }
101         for (final Iterator iterator = bos.entrySet().iterator(); iterator.hasNext()) {
102             Map.Entry entry = (Map.Entryiterator.next();
103             final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBoentry.getValue();
104             Trace.param(CLASS, this, method, "prop", prop);
105             if (!prop.hasLoadedRequiredModules()) {
106                 continue;
107             }
108 
109             // prop must be in dependent list for all required modules
110             final KernelModuleReferenceList refs = prop.getKernelRequiredModules();
111             for (int i = 0; i < refs.size(); i++) {
112                 final DefaultKernelQedeqBo ref = (DefaultKernelQedeqBorefs.getKernelQedeqBo(i);
113                 final KernelModuleReferenceList dependents = ref.getDependentModules();
114                 if (!dependents.contains(prop)) {
115                     Trace.fatal(CLASS, this, method, ref.getUrl() " missing dependent module: "
116                         + prop.getUrl()null);
117                     if (!error) {
118                         url = ref.getUrl();
119                         text = "missing dependent module " + prop.getUrl();
120                     }
121                     error = true;
122                 }
123             }
124 
125             // for all dependent modules, prop must be in required list
126             final KernelModuleReferenceList dependents = prop.getDependentModules();
127             for (int i = 0; i < dependents.size(); i++) {
128                 final DefaultKernelQedeqBo dependent
129                     (DefaultKernelQedeqBodependents.getKernelQedeqBo(i);
130                 final KernelModuleReferenceList refs2 = dependent.getKernelRequiredModules();
131                 if (!refs2.contains(prop)) {
132                     Trace.fatal(CLASS, this, method, dependent.getUrl()
133                         " missing required module: " + prop.getUrl()null);
134                     if (!error) {
135                         url = prop.getUrl();
136                         text = "missing required module " + prop.getUrl();
137                     }
138                     error = true;
139                 }
140             }
141         }
142         Trace.end(CLASS, this, method);
143 
144         // if the dependencies are not ok we throw an error!
145         if (error) {
146             Error e = new Error("QEDEQ dependencies and status are flawed! "
147                 "This is a major error! We do a kernel shutdown!");
148             Trace.fatal(CLASS, this, method, "Shutdown because of major validation error", e);
149             QedeqLog.getInstance().logFailureReply(e.getMessage(), url, text);
150             KernelContext.getInstance().shutdown();
151             throw e;
152         }
153     }
154 
155     /**
156      * Remove a QEDEQ module from memory.
157      *
158      @param   prop    Defines the module.
159      */
160     synchronized void removeModule(final KernelQedeqBo prop) {
161         final String method = "removeModule(KernelQedeqBo)";
162         Trace.begin(CLASS, this, method);
163         try {
164             Trace.trace(CLASS, this, method, "removing " +  prop.getUrl());
165             bos.remove(prop.getModuleAddress());
166         catch (RuntimeException e) {
167             Trace.fatal(CLASS, this, method, "unexpected runtime exception", e);
168             throw e;
169         finally {
170             Trace.end(CLASS, this, method);
171         }
172     }
173 
174     /**
175      * Get list of all successfully loaded modules.
176      *
177      @return  list of all successfully loaded modules.
178      */
179     synchronized ModuleAddress[] getAllLoadedModules() {
180         final String method = "getAllLoadedModules()";
181         Trace.begin(CLASS, this, method);
182         try {
183             final List list = new ArrayList();
184             for (final Iterator iterator = bos.entrySet().iterator(); iterator.hasNext()) {
185                 Map.Entry entry = (Map.Entryiterator.next();
186                 final QedeqBo prop = (QedeqBoentry.getValue();
187                 if (prop.getLoadingState().getCode() >= LoadingState.STATE_LOADED.getCode()) {
188                     list.add(prop.getModuleAddress());
189                 }
190             }
191             return (ModuleAddress[]) list.toArray(new ModuleAddress[list.size()]);
192         finally {
193             Trace.end(CLASS, this, method);
194         }
195     }
196 
197     /**
198      * Get list of all modules.
199      *
200      @return  List of all modules. Values are of type {@link DefaultKernelQedeqBo}.
201      */
202     synchronized List getAllModules() {
203         final String method = "getAllModules()";
204         Trace.begin(CLASS, this, method);
205         try {
206             final List list = new ArrayList();
207             list.addAll(bos.values());
208             return list;
209         finally {
210             Trace.end(CLASS, this, method);
211         }
212     }
213 
214 }