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