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 data) throws 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 first) throws 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, (KernelQedeqBo) imports.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 }
|