Lines 22-27
Link Here
|
22 |
import java.beans.PropertyChangeEvent; |
22 |
import java.beans.PropertyChangeEvent; |
23 |
import java.beans.PropertyChangeListener; |
23 |
import java.beans.PropertyChangeListener; |
24 |
import java.io.BufferedInputStream; |
24 |
import java.io.BufferedInputStream; |
|
|
25 |
import java.io.BufferedOutputStream; |
25 |
import java.io.ByteArrayInputStream; |
26 |
import java.io.ByteArrayInputStream; |
26 |
import java.io.ByteArrayOutputStream; |
27 |
import java.io.ByteArrayOutputStream; |
27 |
import java.io.CharArrayWriter; |
28 |
import java.io.CharArrayWriter; |
Lines 29-47
Link Here
|
29 |
import java.io.FileNotFoundException; |
30 |
import java.io.FileNotFoundException; |
30 |
import java.io.IOException; |
31 |
import java.io.IOException; |
31 |
import java.io.InputStream; |
32 |
import java.io.InputStream; |
|
|
33 |
import java.io.ObjectInputStream; |
32 |
import java.io.ObjectOutput; |
34 |
import java.io.ObjectOutput; |
|
|
35 |
import java.io.ObjectOutputStream; |
33 |
import java.io.OutputStream; |
36 |
import java.io.OutputStream; |
34 |
import java.io.OutputStreamWriter; |
37 |
import java.io.OutputStreamWriter; |
35 |
import java.io.Writer; |
38 |
import java.io.Writer; |
|
|
39 |
import java.util.ArrayList; |
36 |
import java.util.Arrays; |
40 |
import java.util.Arrays; |
|
|
41 |
import java.util.Collection; |
37 |
import java.util.Collections; |
42 |
import java.util.Collections; |
38 |
import java.util.HashMap; |
43 |
import java.util.HashMap; |
39 |
import java.util.HashSet; |
44 |
import java.util.HashSet; |
40 |
import java.util.Iterator; |
45 |
import java.util.Iterator; |
41 |
import java.util.List; |
46 |
import java.util.List; |
42 |
import java.util.Map; |
47 |
import java.util.Map; |
|
|
48 |
import java.util.Properties; |
43 |
import java.util.Set; |
49 |
import java.util.Set; |
44 |
import java.util.TreeMap; |
50 |
import java.util.TreeMap; |
|
|
51 |
import java.util.concurrent.Callable; |
52 |
import java.util.concurrent.ExecutorService; |
53 |
import java.util.concurrent.Executors; |
45 |
import java.util.logging.Level; |
54 |
import java.util.logging.Level; |
46 |
import org.netbeans.DuplicateException; |
55 |
import org.netbeans.DuplicateException; |
47 |
import org.netbeans.Events; |
56 |
import org.netbeans.Events; |
Lines 61-66
Link Here
|
61 |
import org.openide.modules.InstalledFileLocator; |
70 |
import org.openide.modules.InstalledFileLocator; |
62 |
import org.openide.modules.ModuleInstall; |
71 |
import org.openide.modules.ModuleInstall; |
63 |
import org.openide.modules.SpecificationVersion; |
72 |
import org.openide.modules.SpecificationVersion; |
|
|
73 |
import org.openide.util.Exceptions; |
64 |
import org.openide.util.RequestProcessor; |
74 |
import org.openide.util.RequestProcessor; |
65 |
import org.openide.util.Utilities; |
75 |
import org.openide.util.Utilities; |
66 |
import org.openide.util.WeakSet; |
76 |
import org.openide.util.WeakSet; |
Lines 106-116
Link Here
|
106 |
private boolean triggered = false; |
116 |
private boolean triggered = false; |
107 |
/** listener for changes in modules, etc.; see comment on class Listener */ |
117 |
/** listener for changes in modules, etc.; see comment on class Listener */ |
108 |
private final Listener listener = new Listener(); |
118 |
private final Listener listener = new Listener(); |
|
|
119 |
|
120 |
/** Read some stuff from a stream and skip over it. |
121 |
* Newline conventions are normalized to Unix \n. |
122 |
* @return true upon success, false if stream contained something else |
123 |
*/ |
124 |
private boolean expect(InputStream is, byte[] stuff) throws IOException { |
125 |
int len = stuff.length; |
126 |
boolean inNewline = false; |
127 |
for (int i = 0; i < len; ) { |
128 |
int c = is.read(); |
129 |
if (c == 10 || c == 13) { |
130 |
// Normalize: s/[\r\n]+/\n/g |
131 |
if (inNewline) { |
132 |
continue; |
133 |
} else { |
134 |
inNewline = true; |
135 |
c = 10; |
136 |
} |
137 |
} else { |
138 |
inNewline = false; |
139 |
} |
140 |
if (c != stuff[i++]) { |
141 |
return false; |
142 |
} |
143 |
} |
144 |
if (stuff[len - 1] == 10) { |
145 |
// Expecting something ending in a \n - so we have to |
146 |
// read any further \r or \n and discard. |
147 |
if (!is.markSupported()) throw new IOException("Mark not supported"); // NOI18N |
148 |
is.mark(1); |
149 |
int c = is.read(); |
150 |
if (c != -1 && c != 10 && c != 13) { |
151 |
// Got some non-newline character, push it back! |
152 |
is.reset(); |
153 |
} |
154 |
} |
155 |
return true; |
156 |
} |
109 |
/** any module install sers from externalizedModules.ser, from class name to data */ |
157 |
/** any module install sers from externalizedModules.ser, from class name to data */ |
110 |
private final Map<String,byte[]> compatibilitySers = new HashMap<String,byte[]>(100); |
158 |
private final Map<String,byte[]> compatibilitySers = new HashMap<String,byte[]>(100); |
111 |
/** atomic actions I have used to change Modules/*.xml */ |
159 |
/** atomic actions I have used to change Modules/*.xml */ |
112 |
private final Set<FileSystem.AtomicAction> myAtomicActions = Collections.<FileSystem.AtomicAction>synchronizedSet(new WeakSet<FileSystem.AtomicAction>(100)); |
160 |
private final Set<FileSystem.AtomicAction> myAtomicActions = Collections.<FileSystem.AtomicAction>synchronizedSet(new WeakSet<FileSystem.AtomicAction>(100)); |
113 |
|
161 |
private static final String CACHE_FILE_NAME = "modules.cache"; |
114 |
/** Create the list manager. |
162 |
/** Create the list manager. |
115 |
* @param mgr the module manager which will actually control the modules at runtime |
163 |
* @param mgr the module manager which will actually control the modules at runtime |
116 |
* @param folder the Modules/ folder on the system file system to scan/write |
164 |
* @param folder the Modules/ folder on the system file system to scan/write |
Lines 123-128
Link Here
|
123 |
Util.err.fine("ModuleList created, storage in " + folder); |
171 |
Util.err.fine("ModuleList created, storage in " + folder); |
124 |
} |
172 |
} |
125 |
|
173 |
|
|
|
174 |
private boolean errorsLoadingModules = false; |
175 |
private FileObject getCacheFile(boolean create) { |
176 |
FileObject result = folder.getFileObject(CACHE_FILE_NAME); |
177 |
if (result == null && create) { |
178 |
try { |
179 |
result = folder.createData(CACHE_FILE_NAME); |
180 |
} catch (IOException ex) { |
181 |
throw new IllegalStateException (ex); |
182 |
} |
183 |
} |
184 |
return result; |
185 |
} |
186 |
|
187 |
private boolean isCacheUpToDate() { |
188 |
FileObject cacheFile = getCacheFile(false); |
189 |
if (cacheFile == null) { |
190 |
return false; |
191 |
} |
192 |
long date = cacheFile.lastModified().getTime(); |
193 |
boolean result = true; |
194 |
for (FileObject fo : folder.getChildren()) { |
195 |
result &= (fo.lastModified().getTime() <= date); |
196 |
if (!result) { |
197 |
break; |
198 |
} |
199 |
} |
200 |
return result; |
201 |
} |
202 |
|
203 |
public void deleteCacheFile() { |
204 |
FileObject ob = getCacheFile(false); |
205 |
if (ob != null) { |
206 |
try { |
207 |
System.err.println("Deleting module xml cache"); |
208 |
ob.delete(); |
209 |
} catch (IOException ex) { |
210 |
Exceptions.printStackTrace(ex); |
211 |
} |
212 |
} |
213 |
} |
214 |
|
215 |
private void writeCacheFile(Collection <Map <String, Object>> data) throws IOException { |
216 |
if (errorsLoadingModules) { |
217 |
//If some module failed to load, we do not want to write a cache |
218 |
//containing partial data! Otherwise it will silently never be |
219 |
//loaded for eternity. |
220 |
deleteCacheFile(); |
221 |
return; |
222 |
} |
223 |
FileObject ob = getCacheFile(true); |
224 |
|
225 |
FileLock lock = ob.lock(); |
226 |
ObjectOutputStream str = new ObjectOutputStream (new BufferedOutputStream(ob.getOutputStream(lock))); |
227 |
try { |
228 |
str.writeObject(data); |
229 |
} finally { |
230 |
str.close(); |
231 |
lock.releaseLock(); |
232 |
} |
233 |
} |
234 |
|
235 |
private Collection <Map <String, Object>> loadCacheData() { |
236 |
FileObject obj = getCacheFile(false); |
237 |
if (obj != null) { |
238 |
try { |
239 |
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(obj.getInputStream())); |
240 |
return (Collection<Map <String, Object>>) in.readObject(); |
241 |
} catch (Exception ex) { |
242 |
Exceptions.printStackTrace(ex); |
243 |
return null; |
244 |
} |
245 |
} |
246 |
return null; |
247 |
} |
248 |
|
126 |
/** Read an initial list of modules from disk according to their stored settings. |
249 |
/** Read an initial list of modules from disk according to their stored settings. |
127 |
* Just reads the XML files in the Modules/ directory, and adds those to |
250 |
* Just reads the XML files in the Modules/ directory, and adds those to |
128 |
* the manager's list of modules. Errors are handled internally. |
251 |
* the manager's list of modules. Errors are handled internally. |
Lines 131-138
Link Here
|
131 |
* enable as needed. All discovered modules are returned. |
254 |
* enable as needed. All discovered modules are returned. |
132 |
* Write mutex only. |
255 |
* Write mutex only. |
133 |
*/ |
256 |
*/ |
134 |
public Set readInitial() { |
257 |
public Set <Module> readInitial() { |
135 |
ev.log(Events.START_READ); |
258 |
ev.log(Events.START_READ); |
|
|
259 |
if (isCacheUpToDate()) { |
260 |
return readFromCache(); |
261 |
} else { |
262 |
return readFromXml(); |
263 |
} |
264 |
} |
265 |
|
266 |
private Set<Module> readFromCache() { |
267 |
Set<Module> read = new HashSet<Module>(); |
268 |
Collection <Map<String, Object>> data = loadCacheData(); |
269 |
final boolean[] en = new boolean[1]; |
270 |
ev.log( Events.MODULES_FILE_SCANNED, data.size() ); |
271 |
outer: for (Map <String, Object> props : data) { |
272 |
for (Map.Entry <String, Object> e : props.entrySet()) { |
273 |
String name = (String) props.get("name"); |
274 |
String nameDashes = name.replace ('.', '-'); |
275 |
FileObject file = folder.getFileObject (nameDashes + ".xml"); |
276 |
assert file != null; |
277 |
Module m = null; |
278 |
try { |
279 |
m = buildModule (props, name, nameDashes, file, en); |
280 |
} catch (Exception ex) { |
281 |
Exceptions.printStackTrace(ex); |
282 |
//Cache data probably bad |
283 |
errorsLoadingModules = true; |
284 |
deleteCacheFile(); |
285 |
continue outer; |
286 |
} |
287 |
if (m == null) { |
288 |
continue outer; |
289 |
} |
290 |
boolean enabled = en[0]; |
291 |
|
292 |
read.add(m); |
293 |
DiskStatus status = new DiskStatus(); |
294 |
status.module = m; |
295 |
status.file = file; |
296 |
//status.lastApprovedChange = children[i].lastModified().getTime(); |
297 |
status.pendingInstall = enabled; |
298 |
// Will only really be flushed if mgr props != disk props, i.e |
299 |
// if version changed or could not be enabled. |
300 |
//status.pendingFlush = true; |
301 |
status.diskProps = props; |
302 |
statuses.put(name, status); |
303 |
ev.log( Events.MODULES_FILE_PROCESSED, file ); |
304 |
} |
305 |
} |
306 |
// Handle changes in the Modules/ folder on disk by parsing & applying them. |
307 |
folder.addFileChangeListener(FileUtil.weakFileChangeListener (listener, |
308 |
folder)); |
309 |
ev.log(Events.FINISH_READ, read); |
310 |
return read; |
311 |
} |
312 |
|
313 |
private Set<Module> readFromXml() { |
136 |
final Set<Module> read = new HashSet<Module>(); |
314 |
final Set<Module> read = new HashSet<Module>(); |
137 |
try { |
315 |
try { |
138 |
folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { |
316 |
folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { |
Lines 141-147
Link Here
|
141 |
ev.log( Events.MODULES_FILE_SCANNED, children.length ); |
319 |
ev.log( Events.MODULES_FILE_SCANNED, children.length ); |
142 |
|
320 |
|
143 |
XMLReader reader = null; |
321 |
XMLReader reader = null; |
144 |
|
322 |
List <Map <String, Object>> toCache = new ArrayList <Map <String, Object>> (children.length); |
|
|
323 |
final boolean[] en = new boolean[1]; |
145 |
for (int i = 0; i < children.length; i++) { |
324 |
for (int i = 0; i < children.length; i++) { |
146 |
if (children[i].hasExt("ser")) { // NOI18N |
325 |
if (children[i].hasExt("ser")) { // NOI18N |
147 |
// Fine, skip over. |
326 |
// Fine, skip over. |
Lines 149-161
Link Here
|
149 |
// Assume this is one of ours. Note fixed naming scheme. |
328 |
// Assume this is one of ours. Note fixed naming scheme. |
150 |
try { |
329 |
try { |
151 |
String nameDashes = children[i].getName(); // NOI18N |
330 |
String nameDashes = children[i].getName(); // NOI18N |
152 |
char[] badChars = {'.', '/', '>', '='}; |
331 |
char[] chars = nameDashes.toCharArray(); |
153 |
for (int j = 0; j < 4; j++) { |
332 |
for (int j=0; j < chars.length; j++) { |
154 |
if (nameDashes.indexOf(badChars[j]) != -1) { |
333 |
switch (chars[j]) { |
155 |
throw new IllegalArgumentException("Bad name: " + nameDashes); // NOI18N |
334 |
case '.': |
|
|
335 |
case '/' : |
336 |
case '>' : |
337 |
case '=' : |
338 |
throw new IllegalArgumentException("Bad " + |
339 |
"name: " + nameDashes); // NOI18N |
340 |
case '-' : |
341 |
chars[j] = '.'; |
342 |
default: |
343 |
continue; |
156 |
} |
344 |
} |
157 |
} |
345 |
} |
158 |
String name = nameDashes.replace('-', '.').intern(); // NOI18N |
346 |
String name = new String(chars).intern(); |
159 |
// Now name is the code name base of the module we expect to find. |
347 |
// Now name is the code name base of the module we expect to find. |
160 |
// Check its format (throws IllegalArgumentException if bad): |
348 |
// Check its format (throws IllegalArgumentException if bad): |
161 |
Dependency.create(Dependency.TYPE_MODULE, name); |
349 |
Dependency.create(Dependency.TYPE_MODULE, name); |
Lines 186-192
Link Here
|
186 |
} finally { |
374 |
} finally { |
187 |
is.close(); |
375 |
is.close(); |
188 |
} |
376 |
} |
|
|
377 |
toCache.add (props); |
189 |
if (! name.equals(props.get("name"))) throw new IOException("Code name mismatch: " /* #25011 */ + name + " vs. " + props.get("name")); // NOI18N |
378 |
if (! name.equals(props.get("name"))) throw new IOException("Code name mismatch: " /* #25011 */ + name + " vs. " + props.get("name")); // NOI18N |
|
|
379 |
Module m = buildModule (props, name, nameDashes, children[i], en); |
380 |
if (m == null) { |
381 |
continue; |
382 |
} |
383 |
boolean enabled = en[0]; |
384 |
read.add(m); |
385 |
DiskStatus status = new DiskStatus(); |
386 |
status.module = m; |
387 |
status.file = children[i]; |
388 |
//status.lastApprovedChange = children[i].lastModified().getTime(); |
389 |
status.pendingInstall = enabled; |
390 |
// Will only really be flushed if mgr props != disk props, i.e |
391 |
// if version changed or could not be enabled. |
392 |
//status.pendingFlush = true; |
393 |
status.diskProps = props; |
394 |
statuses.put(name, status); |
395 |
} catch (Exception e) { |
396 |
Util.err.log(Level.WARNING, "Error encountered while reading " + children[i], e); |
397 |
errorsLoadingModules = true; |
398 |
} |
399 |
} else { |
400 |
Util.err.fine("Strange file encountered in modules folder: " + children[i]); |
401 |
} |
402 |
ev.log( Events.MODULES_FILE_PROCESSED, children[i] ); |
403 |
} |
404 |
try { |
405 |
writeCacheFile(toCache); |
406 |
} catch (Exception e) { |
407 |
Exceptions.printStackTrace(e); |
408 |
} |
409 |
if (Util.err.isLoggable(Level.FINE)) { |
410 |
Util.err.fine("read initial XML files: statuses=" + statuses); |
411 |
} |
412 |
ev.log(Events.FINISH_READ, read); |
413 |
}}); |
414 |
} catch (IOException ioe) { |
415 |
Util.err.log(Level.WARNING, null, ioe); |
416 |
} |
417 |
return read; |
418 |
} |
419 |
|
420 |
private Module buildModule (Map <String, Object> props, String name, String nameDashes, FileObject fob, boolean[] en) throws IOException, DuplicateException { |
421 |
Module m = mgr.get(name); |
422 |
if (m != null) { |
423 |
return m; |
424 |
} |
190 |
String jar = (String)props.get("jar"); // NOI18N |
425 |
String jar = (String)props.get("jar"); // NOI18N |
191 |
File jarFile; |
426 |
File jarFile; |
192 |
try { |
427 |
try { |
Lines 195-205
Link Here
|
195 |
//Util.err.fine("Cannot find: " + fnfe.getMessage()); |
430 |
//Util.err.fine("Cannot find: " + fnfe.getMessage()); |
196 |
ev.log(Events.MISSING_JAR_FILE, new File(fnfe.getMessage())); |
431 |
ev.log(Events.MISSING_JAR_FILE, new File(fnfe.getMessage())); |
197 |
try { |
432 |
try { |
198 |
children[i].delete(); |
433 |
fob.delete(); |
199 |
} catch (IOException ioe) { |
434 |
} catch (IOException ioe) { |
200 |
Util.err.log(Level.WARNING, null, ioe); |
435 |
Util.err.log(Level.WARNING, null, ioe); |
201 |
} |
436 |
} |
202 |
continue; |
437 |
return null; |
203 |
} |
438 |
} |
204 |
|
439 |
|
205 |
ModuleHistory history = new ModuleHistory(jar); // NOI18N |
440 |
ModuleHistory history = new ModuleHistory(jar); // NOI18N |
Lines 211-216
Link Here
|
211 |
boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); |
446 |
boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); |
212 |
Boolean enabledB = (Boolean)props.get("enabled"); // NOI18N |
447 |
Boolean enabledB = (Boolean)props.get("enabled"); // NOI18N |
213 |
boolean enabled = (enabledB != null ? enabledB.booleanValue() : false); |
448 |
boolean enabled = (enabledB != null ? enabledB.booleanValue() : false); |
|
|
449 |
en[0] = enabled; |
214 |
Boolean autoloadB = (Boolean)props.get("autoload"); // NOI18N |
450 |
Boolean autoloadB = (Boolean)props.get("autoload"); // NOI18N |
215 |
boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); |
451 |
boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); |
216 |
Boolean eagerB = (Boolean)props.get("eager"); // NOI18N |
452 |
Boolean eagerB = (Boolean)props.get("eager"); // NOI18N |
Lines 220-226
Link Here
|
220 |
if (! installer.equals(nameDashes + ".ser")) throw new IOException("Incorrect installer ser name: " + installer); // NOI18N |
456 |
if (! installer.equals(nameDashes + ".ser")) throw new IOException("Incorrect installer ser name: " + installer); // NOI18N |
221 |
// Load from disk in mentioned file. |
457 |
// Load from disk in mentioned file. |
222 |
FileObject installerSer = folder.getFileObject(nameDashes, "ser"); // NOI18N |
458 |
FileObject installerSer = folder.getFileObject(nameDashes, "ser"); // NOI18N |
223 |
if (installerSer == null) throw new IOException("No such install ser: " + installer + "; I see only: " + Arrays.asList(children)); // NOI18N |
459 |
if (installerSer == null) throw new IOException("No such install ser: " + installer); // NOI18N |
224 |
// Hope the stored state is not >Integer.MAX_INT! :-) |
460 |
// Hope the stored state is not >Integer.MAX_INT! :-) |
225 |
byte[] buf = new byte[(int)installerSer.getSize()]; |
461 |
byte[] buf = new byte[(int)installerSer.getSize()]; |
226 |
InputStream is2 = installerSer.getInputStream(); |
462 |
InputStream is2 = installerSer.getInputStream(); |
Lines 233-270
Link Here
|
233 |
// Quasi-prop which is stored separately. |
469 |
// Quasi-prop which is stored separately. |
234 |
props.put("installerState", buf); // NOI18N |
470 |
props.put("installerState", buf); // NOI18N |
235 |
} |
471 |
} |
236 |
Module m = mgr.create(jarFile, history, reloadable, autoload, eager); |
472 |
if (m == null) { |
237 |
read.add(m); |
473 |
m = mgr.create(jarFile, history, reloadable, autoload, eager); |
238 |
DiskStatus status = new DiskStatus(); |
|
|
239 |
status.module = m; |
240 |
status.file = children[i]; |
241 |
//status.lastApprovedChange = children[i].lastModified().getTime(); |
242 |
status.pendingInstall = enabled; |
243 |
// Will only really be flushed if mgr props != disk props, i.e |
244 |
// if version changed or could not be enabled. |
245 |
//status.pendingFlush = true; |
246 |
status.diskProps = props; |
247 |
statuses.put(name, status); |
248 |
} catch (Exception e) { |
249 |
Util.err.log(Level.WARNING, "Error encountered while reading " + children[i], e); |
250 |
} |
474 |
} |
251 |
} else { |
475 |
return m; |
252 |
Util.err.fine("Strange file encountered in modules folder: " + children[i]); |
|
|
253 |
} |
476 |
} |
254 |
ev.log( Events.MODULES_FILE_PROCESSED, children[i] ); |
|
|
255 |
} |
256 |
if (Util.err.isLoggable(Level.FINE)) { |
257 |
Util.err.fine("read initial XML files: statuses=" + statuses); |
258 |
} |
259 |
ev.log(Events.FINISH_READ, read); |
260 |
// Handle changes in the Modules/ folder on disk by parsing & applying them. |
261 |
folder.addFileChangeListener(FileUtil.weakFileChangeListener (listener, folder)); |
262 |
}}); |
263 |
} catch (IOException ioe) { |
264 |
Util.err.log(Level.WARNING, null, ioe); |
265 |
} |
266 |
return read; |
267 |
} |
268 |
|
477 |
|
269 |
/** |
478 |
/** |
270 |
* Try to find a module JAR by an XML-supplied name. |
479 |
* Try to find a module JAR by an XML-supplied name. |
Lines 378-383
Link Here
|
378 |
} |
587 |
} |
379 |
try { |
588 |
try { |
380 |
mgr.enable(modules); |
589 |
mgr.enable(modules); |
|
|
590 |
/* |
591 |
//dangerous but potential perf improvement on multi-core machines. |
592 |
//Certainly unhelpful on single cpu, but worth thinking about |
593 |
//To make this work we really need to walk the dep tree to preserve |
594 |
//ordering and build sets that can be enabled separately |
595 |
int threadCount = 2; |
596 |
final ExecutorService service = Executors.newFixedThreadPool(threadCount); |
597 |
final Object lock = new Object(); |
598 |
final int[] count = new int[] { threadCount }; |
599 |
class R implements Callable <Void> { |
600 |
private final Set <Module> myModules; |
601 |
private final R next; |
602 |
R (R next, Set <Module> myModules) { |
603 |
this.myModules = myModules; |
604 |
this.next = next; |
605 |
} |
606 |
|
607 |
public Void call() throws Exception { |
608 |
System.err.println("Enabling " + myModules + " on " + Thread.currentThread()); |
609 |
mgr.enable(myModules); |
610 |
synchronized (lock) { |
611 |
count[0]--; |
612 |
if (count[0] == 0) { |
613 |
lock.notifyAll(); |
614 |
} |
615 |
} |
616 |
return null; |
617 |
} |
618 |
|
619 |
public void start() throws InvalidException { |
620 |
if (next == null) { |
621 |
try { |
622 |
call(); |
623 |
} catch (Exception e) { |
624 |
if (e instanceof InvalidException) { |
625 |
throw (InvalidException) e; |
626 |
} else { |
627 |
Exceptions.printStackTrace(e); |
628 |
//XXX hard to debug |
629 |
throw new InvalidException (""); |
630 |
} |
631 |
} |
632 |
} else { |
633 |
service.submit(this); |
634 |
next.start(); |
635 |
} |
636 |
} |
637 |
} |
638 |
R prev = null; |
639 |
int ix = 0; |
640 |
int modulesPerThread = modules.size() / threadCount; |
641 |
Set <Module> curr = new HashSet <Module> (modulesPerThread); |
642 |
for (Iterator <Module> iter = modules.iterator(); iter.hasNext(); ix++) { |
643 |
curr.add (iter.next()); |
644 |
if ((ix % modulesPerThread) == 0 || !it.hasNext()) { |
645 |
prev = new R (prev, curr); |
646 |
curr = new HashSet <Module> (modulesPerThread); |
647 |
} |
648 |
} |
649 |
if (prev != null) { |
650 |
//Will cascade and run the last one in this thread |
651 |
prev.start(); |
652 |
} |
653 |
synchronized (lock) { |
654 |
while (count[0] > 0) { |
655 |
lock.wait(); |
656 |
} |
657 |
} |
658 |
} catch (InterruptedException ex) { |
659 |
Exceptions.printStackTrace(ex); |
660 |
*/ |
381 |
} catch (InvalidException ie) { |
661 |
} catch (InvalidException ie) { |
382 |
Util.err.log(Level.WARNING, null, ie); |
662 |
Util.err.log(Level.WARNING, null, ie); |
383 |
Module bad = ie.getModule(); |
663 |
Module bad = ie.getModule(); |
Lines 603-609
Link Here
|
603 |
DefaultHandler handler = new DefaultHandler() { |
883 |
DefaultHandler handler = new DefaultHandler() { |
604 |
private String modName; |
884 |
private String modName; |
605 |
private String paramName; |
885 |
private String paramName; |
606 |
private StringBuffer data = new StringBuffer(); |
886 |
private StringBuilder data = new StringBuilder(); |
607 |
|
887 |
|
608 |
public void startElement(String uri, |
888 |
public void startElement(String uri, |
609 |
String localname, |
889 |
String localname, |
Lines 807-850
Link Here
|
807 |
sanityCheckStatus(m); |
1087 |
sanityCheckStatus(m); |
808 |
return m; |
1088 |
return m; |
809 |
} |
1089 |
} |
810 |
|
|
|
811 |
/** Read some stuff from a stream and skip over it. |
812 |
* Newline conventions are normalized to Unix \n. |
813 |
* @return true upon success, false if stream contained something else |
814 |
*/ |
815 |
private boolean expect(InputStream is, byte[] stuff) throws IOException { |
816 |
int len = stuff.length; |
817 |
boolean inNewline = false; |
818 |
for (int i = 0; i < len; ) { |
819 |
int c = is.read(); |
820 |
if (c == 10 || c == 13) { |
821 |
// Normalize: s/[\r\n]+/\n/g |
822 |
if (inNewline) { |
823 |
continue; |
824 |
} else { |
825 |
inNewline = true; |
826 |
c = 10; |
827 |
} |
828 |
} else { |
829 |
inNewline = false; |
830 |
} |
831 |
if (c != stuff[i++]) { |
832 |
return false; |
833 |
} |
834 |
} |
835 |
if (stuff[len - 1] == 10) { |
836 |
// Expecting something ending in a \n - so we have to |
837 |
// read any further \r or \n and discard. |
838 |
if (!is.markSupported()) throw new IOException("Mark not supported"); // NOI18N |
839 |
is.mark(1); |
840 |
int c = is.read(); |
841 |
if (c != -1 && c != 10 && c != 13) { |
842 |
// Got some non-newline character, push it back! |
843 |
is.reset(); |
844 |
} |
845 |
} |
846 |
return true; |
847 |
} |
848 |
/** Read a maximal string until delim is encountered (which will be removed from stream). |
1090 |
/** Read a maximal string until delim is encountered (which will be removed from stream). |
849 |
* This impl reads only ASCII, for speed. |
1091 |
* This impl reads only ASCII, for speed. |
850 |
* Newline conventions are normalized to Unix \n. |
1092 |
* Newline conventions are normalized to Unix \n. |