LoadRequiredModules.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2011,  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.trace.Trace;
022 import org.qedeq.kernel.bo.module.KernelModuleReferenceList;
023 import org.qedeq.kernel.se.common.DefaultSourceFileExceptionList;
024 import org.qedeq.kernel.se.common.DependencyState;
025 import org.qedeq.kernel.se.common.ModuleDataException;
026 import org.qedeq.kernel.se.common.Plugin;
027 import org.qedeq.kernel.se.common.SourceFileException;
028 import org.qedeq.kernel.se.common.SourceFileExceptionList;
029 
030 
031 /**
032  * Load all required QEDEQ modules.
033  *
034  @author  Michael Meyling
035  */
036 public final class LoadRequiredModules {
037 
038     /** This class. */
039     private static final Class CLASS = LoadRequiredModules.class;
040 
041     /** All QedeqBos currently in state "loading required modules". */
042     private final Map loadingRequiredInProgress = new HashMap();
043 
044     /**
045      * Don't use this constructor.
046      */
047     private LoadRequiredModules() {
048         // nothing to do
049     }
050 
051     /**
052      * Load all required QEDEQ modules for a given QEDEQ module.
053      *
054      @param   plugin      We work for this plugin.
055      @param   prop        QEDEQ module BO. This module must be loaded.
056      @return  Loading successful.
057      @throws  IllegalArgumentException    BO is not loaded
058      */
059     public static boolean loadRequired(final Plugin plugin, final DefaultKernelQedeqBo prop) {
060         // did we check this already?
061         if (prop.getDependencyState().areAllRequiredLoaded()) {
062             return true// everything is OK
063         }
064         return (new LoadRequiredModules()).loadAllRequired(plugin, prop);
065     }
066 
067     /**
068      * Load all required QEDEQ modules for a given QEDEQ module.
069      *
070      @param   plugin      We work for this plugin.
071      @param   prop        QEDEQ module BO. This module must be loaded.
072      @return  Loading successful.
073      @throws  IllegalArgumentException    BO is not loaded
074      */
075     private boolean loadAllRequired(final Plugin plugin, final DefaultKernelQedeqBo prop) {
076         final String method = "loadRequired(DefaultQedeqBo)";
077         Trace.param(CLASS, this, method, "prop.getModuleAddress", prop.getModuleAddress());
078         synchronized (prop) {
079             if (prop.getDependencyState().areAllRequiredLoaded()) {
080                 return true// everything is OK
081             }
082             if (!prop.isLoaded()) {
083                 throw new IllegalArgumentException("Programming error BO must be loaded!");
084             }
085             if (loadingRequiredInProgress.containsKey(prop)) { // already checked?
086                 throw new IllegalStateException("Programming error: must not be marked!");
087             }
088             prop.setDependencyProgressState(DependencyState.STATE_LOADING_REQUIRED_MODULES);
089             loadingRequiredInProgress.put(prop, prop);
090 
091         }
092         SourceFileExceptionList sfl = null;
093         final LoadDirectlyRequiredModules loader = new LoadDirectlyRequiredModules(plugin, prop);
094         KernelModuleReferenceList required = null;
095         try {
096             required = loader.load();
097             sfl = loader.getErrorList();
098         catch (SourceFileExceptionList e) {
099             sfl = e;
100         }
101         if (sfl == null || sfl.size() == 0) {
102             for (int i = 0; i < required.size(); i++) {
103                 Trace.trace(CLASS, this, method, "loading required modules of " + prop.getUrl());
104                 DefaultKernelQedeqBo current = null;
105                 current = (DefaultKernelQedeqBorequired.getKernelQedeqBo(i);
106                 if (loadingRequiredInProgress.containsKey(current)) {
107                     ModuleDataException me = new LoadRequiredModuleException(
108                         ServiceErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_CODE,
109                         ServiceErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_TEXT + "\""
110                         + required.getLabel(i"\"",
111                         required.getModuleContext(i));
112                     final SourceFileException sf = prop.createSourceFileException(plugin, me);
113                     if (sfl == null) {
114                         sfl = new DefaultSourceFileExceptionList(sf);
115                     else {
116                         sfl.add(sf);
117                     }
118                     continue;
119                 }
120                 if (!loadAllRequired(plugin, current)) {
121                     // LATER 20110119 m31: we take only the first error, is that ok?
122                     ModuleDataException me = new LoadRequiredModuleException(
123                         ServiceErrors.IMPORT_OF_MODULE_FAILED_CODE,
124                         ServiceErrors.IMPORT_OF_MODULE_FAILED_TEXT + "\"" + required.getLabel(i)
125                             "\", " + current.getErrors().get(0).getMessage(),
126                     required.getModuleContext(i));
127                     final SourceFileException sf = prop.createSourceFileException(plugin, me);
128                     if (sfl == null) {
129                         sfl = new DefaultSourceFileExceptionList(sf);
130                     else {
131                         sfl.add(sf);
132                     }
133                     continue;
134                 }
135             }
136         }
137 
138         synchronized (prop) {
139             loadingRequiredInProgress.remove(prop);
140             if (prop.getDependencyState().areAllRequiredLoaded()) {
141                 return true// everything is OK, someone elses thread might have corrected errors!
142             }
143             prop.getLabels().setModuleReferences(required);
144             if (sfl == null || sfl.size() == 0) {
145                 prop.setLoadedRequiredModules(required);
146                 return true;
147             else {
148                 prop.setDependencyFailureState(
149                     DependencyState.STATE_LOADING_REQUIRED_MODULES_FAILED, sfl);
150                 return false;
151             }
152         }
153     }
154 
155 }