LoadRequiredModulesExecutor.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.dependency;
017 
018 import java.util.Stack;
019 
020 import org.qedeq.base.io.Parameters;
021 import org.qedeq.base.trace.Trace;
022 import org.qedeq.base.utility.StringUtility;
023 import org.qedeq.kernel.bo.common.ModuleReferenceList;
024 import org.qedeq.kernel.bo.log.QedeqLog;
025 import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
026 import org.qedeq.kernel.bo.module.KernelModuleReferenceList;
027 import org.qedeq.kernel.bo.module.KernelQedeqBo;
028 import org.qedeq.kernel.bo.service.basis.ControlVisitor;
029 import org.qedeq.kernel.bo.service.basis.ModuleServicePluginExecutor;
030 import org.qedeq.kernel.se.common.ModuleDataException;
031 import org.qedeq.kernel.se.common.ModuleService;
032 import org.qedeq.kernel.se.common.SourceFileException;
033 import org.qedeq.kernel.se.common.SourceFileExceptionList;
034 import org.qedeq.kernel.se.state.DependencyState;
035 import org.qedeq.kernel.se.visitor.InterruptException;
036 
037 
038 /**
039  * Load all required QEDEQ modules.
040  *
041  @author  Michael Meyling
042  */
043 public final class LoadRequiredModulesExecutor extends ControlVisitor implements ModuleServicePluginExecutor {
044 
045     /** This class. */
046     private static final Class CLASS = LoadRequiredModulesExecutor.class;
047 
048     /** Percentage between 0 and 100. */
049     private double percentage;
050 
051     /**
052      * Constructor.
053      *
054      @param   plugin      Plugin we work for.
055      @param   prop        Internal QedeqBo.
056      @param   parameters  Currently ignored.
057      */
058     LoadRequiredModulesExecutor(final ModuleService plugin, final KernelQedeqBo prop,
059             final Parameters parameters) {
060         super(plugin, prop);
061     }
062 
063     public Object executePlugin(final InternalModuleServiceCall call, final Object datathrows InterruptException {
064         percentage = 0;
065         final String method = "executePlugin";
066         if (getKernelQedeqBo().hasLoadedRequiredModules()) {
067             percentage = 100;
068             return Boolean.TRUE; // everything is OK
069         }
070         QedeqLog.getInstance().logRequest(
071             "Loading required modules", getKernelQedeqBo().getUrl());
072         // all QedeqBos currently in state "loading required modules"
073 
074         if (!loadAllRequiredModules(call, getKernelQedeqBo()true)) {
075             final String msg = "Loading required modules failed";
076             QedeqLog.getInstance().logFailureReply(msg, getKernelQedeqBo().getUrl(),
077                 "Not all required modules could not even be loaded.");
078             return Boolean.FALSE;
079         }
080         percentage = 100;
081         Trace.trace(CLASS, this, method, "loading required modules of " + getKernelQedeqBo().getUrl());
082         getKernelQedeqBo().setDependencyProgressState(DependencyState.STATE_LOADING_REQUIRED_MODULES);
083 
084 
085         final SourceFileExceptionList sfl = new SourceFileExceptionList();
086         if (circlesInRequiredModules(call, getKernelQedeqBo(), sfl)) {
087             final String msg = "Loading required modules failed";
088             QedeqLog.getInstance().logFailureReply(msg, getKernelQedeqBo().getUrl(),
089                 "There were circular dependencies.");
090             return Boolean.FALSE;
091         }
092 
093         if (getKernelQedeqBo().getDependencyState().areAllRequiredLoaded()) {
094             return Boolean.TRUE; // everything is OK, someone else's thread might have corrected errors!
095         }
096 
097         getKernelQedeqBo().getLabels().setModuleReferences(getKernelQedeqBo().getRequiredModules())// FIXME why here?
098         if (!getKernelQedeqBo().hasBasicFailures() && sfl.size() == 0) {
099             getKernelQedeqBo().setLoadedRequiredModules();
100             QedeqLog.getInstance().logSuccessfulReply(
101                 "Loading required modules successful", getKernelQedeqBo().getUrl());
102             return Boolean.TRUE;
103         }
104         if (sfl.size() != 0) {
105             getKernelQedeqBo().setDependencyFailureState(
106                 DependencyState.STATE_LOADING_REQUIRED_MODULES_FAILED, sfl);
107         else {
108             getKernelQedeqBo().setDependencyFailureState(
109                 DependencyState.STATE_LOADING_REQUIRED_MODULES_FAILED, getKernelQedeqBo().getErrors());
110         }
111         final String msg = "Loading required modules failed";
112         QedeqLog.getInstance().logFailureReply(msg, getKernelQedeqBo().getUrl(),
113              StringUtility.replace(getKernelQedeqBo().getErrors().getMessage()"\n""\n\t"));
114         return  Boolean.FALSE;
115     }
116 
117     private boolean circlesInRequiredModules(final InternalModuleServiceCall call, final KernelQedeqBo bo,
118             final SourceFileExceptionList sfl) {
119         if (bo.hasLoadedRequiredModules()) {
120             return false;
121         }
122         Stack loadingRequiredInProgress = new Stack();
123         Stack labels = new Stack();
124 //        System.out.println("->checking " + bo.getName());
125         loadingRequiredInProgress.push(bo);
126         final KernelModuleReferenceList required = bo.getKernelRequiredModules();
127         final StringBuffer error = new StringBuffer();
128         for (int i = 0; i < required.size(); i++) {
129             final KernelQedeqBo current = required.getKernelQedeqBo(i);
130 //            System.out.println("-->testing " + current.getName());
131             labels.push(required.getLabel(i));
132             if (loadingRequiredInProgress.contains(current)) {
133 //                for (int j = 0; j < loadingRequiredInProgress.size(); j++) {
134 //                    System.out.print("-> " + labels.get(j).toString());
135 //                }
136                 ModuleDataException me = new LoadRequiredModuleException(
137                     DependencyErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_CODE,
138                     DependencyErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_TEXT + "\""
139                     + required.getLabel(i"\"",
140                     required.getModuleContext(i));
141                 sfl.add(createError(me));
142 //                me.printStackTrace(System.out);
143                 labels.pop();
144                 continue;
145             }
146 
147 //            System.out.println("->removing " + bo.getName());
148 //            loadingRequiredInProgress.remove(bo);
149             error.setLength(0);
150             if (!noCirclesInRequiredModules(call, required.getKernelQedeqBo(i), loadingRequiredInProgress, labels,
151                     error)) {
152                 // LATER 20110119 m31: we take only the first error, is that ok?
153                 String text = DependencyErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_TEXT + error.toString();
154                 ModuleDataException me = new LoadRequiredModuleException(
155                     DependencyErrors.RECURSIVE_IMPORT_OF_MODULES_IS_FORBIDDEN_CODE,
156                     text, required.getModuleContext(i));
157                 sfl.add(createError(me));
158             }
159             labels.pop();
160         }
161 //        System.out.println("->removing " + bo.getName());
162         loadingRequiredInProgress.pop();
163         if (sfl.size() 0) {
164             bo.setDependencyFailureState(DependencyState.STATE_LOADING_REQUIRED_MODULES_FAILED, sfl);
165             return true;
166         }
167         return false;
168     }
169 
170     private boolean noCirclesInRequiredModules(final InternalModuleServiceCall call, final KernelQedeqBo bo,
171             final Stack loadingRequiredInProgress, final Stack labels, final StringBuffer error) {
172         if (!bo.hasLoadedImports()) {
173             return false;
174         }
175 //        System.out.println("->checking " + bo.getName());
176         loadingRequiredInProgress.push(bo);
177         final KernelModuleReferenceList required = bo.getKernelRequiredModules();
178         boolean result = true;
179         for (int i = 0; i < required.size(); i++) {
180             final KernelQedeqBo current = required.getKernelQedeqBo(i);
181 //            System.out.println("-->testing " + current.getName() + " (" + required.getLabel(i) + ")");
182             labels.push(required.getLabel(i));
183             if (loadingRequiredInProgress.contains(current)) {
184                 for (int j = 0; j < loadingRequiredInProgress.size(); j++) {
185                     if (j > 0) {
186                         error.append(" -> ");
187                     }
188                     error.append("\"" + labels.get(j).toString() "\"");
189                 }
190                 result = false;
191 //                System.out.println("## " + error);
192                 labels.pop();
193                 break;
194             }
195 
196             if (!noCirclesInRequiredModules(call, required.getKernelQedeqBo(i), loadingRequiredInProgress, labels,
197                     error)) {
198                 result = false;
199 //                System.out.println("## " + error);
200                 labels.pop();
201                 break;
202             }
203             labels.pop();
204         }
205 //        System.out.println("->removing " + bo.getName());
206         loadingRequiredInProgress.pop();
207         return result;
208     }
209 
210     private boolean loadAllRequiredModules(final InternalModuleServiceCall call, final KernelQedeqBo bo,
211             final boolean firstthrows InterruptException {
212         if (bo.hasLoadedImports()) {
213             return true;
214         }
215         getServices().executePlugin(call.getInternalServiceProcess(),
216             LoadDirectlyRequiredModulesPlugin.class.getName(), bo, null);
217         if (!bo.hasLoadedImports()) {
218             return false;
219         }
220         final ModuleReferenceList imports = bo.getRequiredModules();
221         final SourceFileExceptionList sfl = new SourceFileExceptionList();
222         boolean result = true;
223         for (int i = 0; i < imports.size(); i++) {
224             if (!imports.getQedeqBo(i).hasLoadedImports()) {
225                 if (!loadAllRequiredModules(call, (KernelQedeqBoimports.getQedeqBo(i)false)) {
226                     result = false;
227                     if (first) {
228                         // LATER 20110119 m31: we take only the first error, is that ok?
229                         String text = DependencyErrors.IMPORT_OF_MODULE_FAILED_TEXT + "\""
230                             + imports.getLabel(i"\"";
231                         if (imports.getQedeqBo(i).getErrors().size() 0) {
232                             text += ", " + imports.getQedeqBo(i).getErrors().get(0).getMessage();
233                         }
234                         ModuleDataException me = new LoadRequiredModuleException(
235                             DependencyErrors.IMPORT_OF_MODULE_FAILED_CODE,
236                             text, imports.getModuleContext(i));
237                         sfl.add(createError(me));
238                     }
239                 }
240             }
241         }
242         if (sfl.size() 0) {
243             bo.setDependencyFailureState(DependencyState.STATE_LOADING_REQUIRED_MODULES_FAILED, sfl);
244         }
245         return result;
246     }
247 
248     public double getVisitPercentage() {
249         return percentage;
250     }
251 
252     public boolean getInterrupted() {
253         return false;
254     }
255 
256     public String getLocationDescription() {
257         return super.getLocationDescription();
258     }
259 
260 
261     /**
262      * Prepare exception for error collection.
263      *
264      @param   me  Basis exception.
265      @return  Error.
266      */
267     private SourceFileException createError(final ModuleDataException me) {
268         return getKernelQedeqBo().createSourceFileException(getService(), me);
269     }
270 
271 }