1 | package de.uka.ipd.sdq.pcmsolver.transformations.pcm2lqn; |
2 | |
3 | import java.io.BufferedReader; |
4 | import java.io.FileInputStream; |
5 | import java.io.FileNotFoundException; |
6 | import java.io.IOException; |
7 | import java.io.InputStream; |
8 | import java.io.InputStreamReader; |
9 | import java.text.DateFormat; |
10 | import java.text.SimpleDateFormat; |
11 | import java.util.Date; |
12 | import java.util.List; |
13 | import java.util.concurrent.TimeUnit; |
14 | |
15 | import org.apache.log4j.Logger; |
16 | import org.eclipse.swt.widgets.Display; |
17 | import org.eclipse.ui.IWorkbenchPage; |
18 | import org.eclipse.ui.PartInitException; |
19 | import org.eclipse.ui.PlatformUI; |
20 | |
21 | import LqnCore.LqnModelType; |
22 | |
23 | import de.uka.ipd.sdq.pcm.usagemodel.UsageScenario; |
24 | import de.uka.ipd.sdq.pcmsolver.models.PCMInstance; |
25 | import de.uka.ipd.sdq.pcmsolver.runconfig.MessageStrings; |
26 | import de.uka.ipd.sdq.pcmsolver.runconfig.PCMSolverWorkflowRunConfiguration; |
27 | import de.uka.ipd.sdq.pcmsolver.transformations.ContextWrapper; |
28 | import de.uka.ipd.sdq.pcmsolver.transformations.SolverStrategy; |
29 | import de.uka.ipd.sdq.pcmsolver.visitors.UsageModelVisitor; |
30 | import de.uka.ipd.sdq.pcmsolver.visualisation.LQNHtmlResultGenerator; |
31 | import de.uka.ipd.sdq.pcmsolver.visualisation.LQNResultEditorInput; |
32 | |
33 | /** |
34 | * This is an excerpt of Heiko's dissertation (see below for link) |
35 | * |
36 | * The Layered Queueing Network (LQN) model is a performance model in the class |
37 | * of extended queueing networks. It is a popular model with widespread use |
38 | * [BDIS04]. Like the PCM, it specifically targets analysing the performance of |
39 | * distributed systems. While ordinary queueing networks model software |
40 | * structures only implicitly via resource demands to service centers, LQNs |
41 | * model a system as a layered hierarchy of interacting software entities, which |
42 | * produce demands for the underlying physical resources such as CPUs or hard |
43 | * disks. Therefore, LQNs reflect the structure of distributed systems more |
44 | * naturally than ordinary queueing networks. In particular, they model the |
45 | * routing of jobs in the network more realistically. |
46 | * |
47 | * In the context of this work, a model transformation from PCM instances (with |
48 | * computed context models) to LQNs has been implemented. The transformation |
49 | * offers at least two advantages: First, it enables comparing the concepts of |
50 | * the PCM with concepts of LQNs, which can be considered as a state-of-the-art |
51 | * performance model. Second, the transformation makes the sophisticated |
52 | * analytical solvers and simulation tools for LQNs available to the PCM. Other |
53 | * than SREs, LQNs support concurrent behaviour, different kinds of workloads, |
54 | * asynchronous interactions, and different scheduling strategies. Therefore, it |
55 | * is possible to derive performance metrics such as resource utilizations and |
56 | * throughput from PCM instances, which is not possible with SREs. However, LQNs |
57 | * are restricted to exponential distributions and mean-values analysis as |
58 | * discussed later. |
59 | * |
60 | * The chapter 6.4 in Heiko's dissertation will first provide some background |
61 | * about LQNs and their development in recent years (Chapter 6.4.2). Then, it |
62 | * will describe the syntax and (informal) semantics of LQNs using the LQN |
63 | * meta-model and several examples (Chapter 6.4.3). Chapter 6.4.4 briefly |
64 | * describes two performance solvers for LQNs, before Chapter 6.4.5 presents the |
65 | * mapping from PCM instances to LQN instances. Finally, Chapter 6.4.6 compares |
66 | * the PCM model with the LQN model, as well as the existing PCM solvers with |
67 | * two available LQN solvers. |
68 | * |
69 | * @see Heiko's dissertation, section 6.4 at |
70 | * http://docserver.bis.uni-oldenburg.de |
71 | * /_publikationen/dissertation/2008/kozpar08/pdf/kozpar08.pdf |
72 | * @author Heiko Koziolek |
73 | * |
74 | */ |
75 | public class Pcm2LqnStrategy implements SolverStrategy { |
76 | |
77 | private static Logger logger = Logger.getLogger(Pcm2LqnStrategy.class |
78 | .getName()); |
79 | |
80 | // the following filenames should be OS-independent |
81 | private String filenameInputXML; |
82 | private String filenameResultHumanReadable; |
83 | private String filenameResultXML; |
84 | private String filenameLQN; |
85 | |
86 | // the lqn tools should be in the system path |
87 | private static final String FILENAME_LQNS = "lqns"; |
88 | private static final String FILENAME_LQSIM = "lqsim"; |
89 | private static final String FILENAME_LQN2XML = "lqn2xml"; |
90 | |
91 | // Return values of lqns |
92 | private static final int LQNS_RETURN_SUCCESS = 0; |
93 | private static final int LQNS_RETURN_MODEL_FAILED_TO_CONVERGE = 1; |
94 | private static final int LQNS_RETURN_INVALID_INPUT = 2; |
95 | private static final int LQNS_RETURN_FATAL_ERROR = -1; |
96 | |
97 | private long overallDuration = 0; |
98 | private PCMSolverWorkflowRunConfiguration config; |
99 | |
100 | public Pcm2LqnStrategy(PCMSolverWorkflowRunConfiguration configuration) { |
101 | config = configuration; |
102 | |
103 | DateFormat dateFormat = new SimpleDateFormat("-yyyy-MM-dd-HHmmss"); |
104 | Date date = new Date(); |
105 | String timestamp = dateFormat.format(date); |
106 | |
107 | filenameInputXML = getOutputFolder() |
108 | + System.getProperty("file.separator") + "pcm2lqn" + timestamp |
109 | + ".xml"; |
110 | filenameResultHumanReadable = getOutputFolder() |
111 | + System.getProperty("file.separator") + "pcm2lqn" + timestamp |
112 | + ".out"; |
113 | filenameResultXML = getOutputFolder() |
114 | + System.getProperty("file.separator") + "pcm2lqn_result" |
115 | + timestamp + ".xml"; |
116 | filenameLQN = getOutputFolder() + System.getProperty("file.separator") |
117 | + "pcm2lqn" + timestamp + ".lqn"; |
118 | } |
119 | |
120 | public String getFilenameResultXML() { |
121 | return filenameResultXML; |
122 | } |
123 | |
124 | private String getOutputFolder() { |
125 | if (getSolverProgramName().equals(FILENAME_LQNS)) { |
126 | return config.getLqnsOutputDir(); |
127 | } else { |
128 | return config.getLqsimOutputDir(); |
129 | } |
130 | } |
131 | |
132 | public Pcm2LqnStrategy() { |
133 | } |
134 | |
135 | public void loadTransformedModel(String fileName) { |
136 | } |
137 | |
138 | public void solve() { |
139 | String solverProgram = getSolverProgramName(); |
140 | String lqnsOutputType = getLqnsOutputTypeName(); |
141 | String lqnSimOutputType = getLqsimOutputTypeName(); |
142 | |
143 | String options = ""; |
144 | |
145 | String resultFile = ""; |
146 | String inputFile = ""; |
147 | |
148 | long timeBeforeCalc = System.nanoTime(); |
149 | |
150 | int exitVal = LQNS_RETURN_FATAL_ERROR; |
151 | String errorMessages = ""; |
152 | |
153 | try { |
154 | String command = ""; |
155 | |
156 | |
157 | |
158 | // Process proc = null; |
159 | if (solverProgram.equals(FILENAME_LQNS)) { |
160 | |
161 | // check whether Pragmas (see LQN documentation) are used and if yes, set -P option |
162 | if (!config.getStopOnMessageLossLQNS() |
163 | || !"".equals(config.getPragmas())){ |
164 | options += " -P "; |
165 | if (!config.getStopOnMessageLossLQNS()){ |
166 | options += "stop-on-message-loss=false "; |
167 | } |
168 | if (!"".equals(config.getPragmas())){ |
169 | options += config.getPragmas(); |
170 | } |
171 | } |
172 | if (lqnsOutputType.equals(MessageStrings.LQN_OUTPUT_HUMAN) |
173 | ) { |
174 | inputFile = filenameLQN; |
175 | resultFile = filenameResultHumanReadable; |
176 | command = solverProgram |
177 | + options |
178 | + " -o" + resultFile + " " + inputFile; |
179 | } else if (lqnsOutputType.equals(MessageStrings.LQN_OUTPUT_XML) |
180 | || lqnsOutputType.equals(MessageStrings.LQN_OUTPUT_HTML)) { |
181 | // The lqns produces XML output when the input is as well in |
182 | // XML |
183 | inputFile = filenameResultXML; |
184 | resultFile = inputFile; |
185 | command = solverProgram |
186 | + options |
187 | + " " + inputFile; |
188 | } |
189 | } else if (solverProgram.equals(FILENAME_LQSIM)) { |
190 | // LQSim config |
191 | String blocks = config.getLQSimBlocks(); |
192 | String runtime = config.getLQSimRuntime(); |
193 | |
194 | if (runtime != null && runtime != ""){ |
195 | options += " -A "+runtime; |
196 | } |
197 | if (blocks != null && blocks != ""){ |
198 | options += " -B "+blocks; |
199 | } |
200 | if (!config.getStopOnMessageLossLQSim()){ |
201 | options += " -P stop-on-message-loss=false"; |
202 | } |
203 | |
204 | if (lqnSimOutputType.equals(MessageStrings.LQN_OUTPUT_HUMAN) |
205 | || lqnSimOutputType.equals(MessageStrings.LQN_OUTPUT_HTML)) { |
206 | inputFile = filenameLQN; |
207 | resultFile = filenameResultHumanReadable; |
208 | command = solverProgram |
209 | + options |
210 | + " -o" + resultFile + " " + inputFile; |
211 | } else if (lqnSimOutputType |
212 | .equals(MessageStrings.LQN_OUTPUT_XML)) { |
213 | // The lqsim produces XML output when the input is as well |
214 | // in XML |
215 | inputFile = filenameResultXML; |
216 | resultFile = inputFile; |
217 | command = solverProgram |
218 | + options |
219 | + " " + inputFile; |
220 | } |
221 | } |
222 | logger.warn("Calling LQN analysis tool with "+command); |
223 | ProcessBuilder pb = new ProcessBuilder(splitToCommandArray(command)); |
224 | pb.redirectErrorStream(true); |
225 | Process proc = pb.start(); |
226 | |
227 | // StreamGobbler errorGobbler = new |
228 | // StreamGobbler(proc.getErrorStream(), "ERROR"); |
229 | // StreamGobbler outputGobbler = new |
230 | // StreamGobbler(proc.getInputStream(), "OUTPUT"); |
231 | // errorGobbler.start(); |
232 | // outputGobbler.start(); |
233 | |
234 | errorMessages = readStream(proc.getInputStream()); |
235 | |
236 | exitVal = proc.waitFor(); |
237 | proc.destroy(); |
238 | |
239 | } catch (Throwable e) { |
240 | logger.error("Running " + solverProgram + " failed!"); |
241 | throw new RuntimeException(e); |
242 | } |
243 | |
244 | long timeAfterCalc = System.nanoTime(); |
245 | long duration = TimeUnit.NANOSECONDS.toMillis(timeAfterCalc |
246 | - timeBeforeCalc); |
247 | overallDuration += duration; |
248 | logger.warn("Finished Running " + solverProgram + ":\t\t" + duration |
249 | + " ms"); |
250 | logger |
251 | .warn("Completed Analysis:\t\t" + overallDuration |
252 | + " ms overall"); |
253 | |
254 | /* return if results are available or throw exception. */ |
255 | if (exitVal == LQNS_RETURN_SUCCESS) { |
256 | logger.warn("Analysis Result has been written to: " + resultFile); |
257 | if (lqnsOutputType.equals(MessageStrings.LQN_OUTPUT_HTML)){ |
258 | //showOutput(resultFile); |
259 | LQNHtmlResultGenerator result = new LQNHtmlResultGenerator(resultFile); |
260 | result.display(); |
261 | } |
262 | |
263 | } else if (exitVal == LQNS_RETURN_MODEL_FAILED_TO_CONVERGE){ |
264 | logger.error(solverProgram + " exited with " + exitVal |
265 | + ": The model failed to converge. Results are most likely inaccurate. "); |
266 | logger.warn("Analysis Result has been written to: " + resultFile); |
267 | } else { |
268 | String message = ""; |
269 | if (exitVal == LQNS_RETURN_INVALID_INPUT) { |
270 | message = solverProgram + " exited with " + exitVal |
271 | + ": Invalid Input."; |
272 | } else if (exitVal == LQNS_RETURN_FATAL_ERROR) { |
273 | message = solverProgram + " exited with " + exitVal |
274 | + ": Fatal error"; |
275 | } else { |
276 | message = solverProgram |
277 | + " returned an unrecognised exit value " |
278 | + exitVal |
279 | + ". Key: 0 on success, 1 if the model failed to meet the convergence criteria, 2 if the input was invalid, 4 if a command line argument was incorrect, 8 for file read/write problems and -1 for fatal errors. If multiple input files are being processed, the exit code is the bit-wise OR of the above conditions."; |
280 | } |
281 | message += "\nFurther errors: "+errorMessages; |
282 | logger.error(message); |
283 | throw new RuntimeException(message); |
284 | } |
285 | } |
286 | |
287 | private String getSolverProgramName() { |
288 | if (config.getSolver().equals(MessageStrings.LQNS_SOLVER)) { |
289 | return FILENAME_LQNS; |
290 | } else { |
291 | return FILENAME_LQSIM; |
292 | } |
293 | } |
294 | |
295 | private String getLqnsOutputTypeName() { |
296 | return config.getLqnsOutput(); |
297 | } |
298 | |
299 | private String getLqsimOutputTypeName() { |
300 | return config.getLqsimOutput(); |
301 | } |
302 | |
303 | /** |
304 | * Reads the output file and shows its content in a new text editor window. |
305 | * |
306 | * @param filename |
307 | */ |
308 | private void showOutput(String filename) { |
309 | FileInputStream fis = null; |
310 | byte b[] = null; |
311 | try { |
312 | fis = new FileInputStream(filename); |
313 | int x = 0; |
314 | x = fis.available(); |
315 | b = new byte[x]; |
316 | fis.read(b); |
317 | fis.close(); |
318 | } catch (FileNotFoundException e) { |
319 | e.printStackTrace(); |
320 | } catch (IOException e) { |
321 | e.printStackTrace(); |
322 | } |
323 | |
324 | String content = new String(b); |
325 | |
326 | final String htmlText = getHtmlForLqnResult(content); |
327 | |
328 | // ResultWindow rw = new ResultWindow(content); |
329 | // rw.open(); |
330 | |
331 | Display.getDefault().asyncExec(new Runnable() { |
332 | public void run() { |
333 | IWorkbenchPage page = PlatformUI.getWorkbench() |
334 | .getActiveWorkbenchWindow().getActivePage(); |
335 | if (page != null) { |
336 | try { |
337 | page.openEditor(new LQNResultEditorInput(htmlText), |
338 | "de.uka.ipd.sdq.pcmsolver.LQNResultEditor"); |
339 | } catch (PartInitException e) { |
340 | e.printStackTrace(); |
341 | } |
342 | } |
343 | } |
344 | }); |
345 | |
346 | } |
347 | |
348 | private String getHtmlForLqnResult(String lqnResult) { |
349 | String htmlText = "<html><head><title>LQN Results</title></head>" + |
350 | "<body><pre>" + |
351 | lqnResult + |
352 | "</pre></body></html>"; |
353 | return htmlText; |
354 | } |
355 | |
356 | public void storeTransformedModel(String fileName) { |
357 | } |
358 | |
359 | public void transform(PCMInstance model) { |
360 | long startTime = System.nanoTime(); |
361 | |
362 | runDSolver(model); |
363 | |
364 | long timeAfterDSolve = System.nanoTime(); |
365 | long duration = TimeUnit.NANOSECONDS.toMillis(timeAfterDSolve |
366 | - startTime); |
367 | overallDuration += duration; |
368 | logger.warn("Finished DSolver:\t\t" + duration + " ms"); |
369 | |
370 | long timeBeforeTransform = System.nanoTime(); |
371 | |
372 | // model.saveComputedContextToFiles(System.getProperty("user.dir") |
373 | // + System.getProperty("file.separator")+"computedContexts"); |
374 | |
375 | runPcm2Lqn(model); |
376 | |
377 | long timeAfterTransform = System.nanoTime(); |
378 | long duration2 = TimeUnit.NANOSECONDS.toMillis(timeAfterTransform |
379 | - timeBeforeTransform); |
380 | overallDuration += duration2; |
381 | logger.warn("Finished PCM2LQN:\t\t" + duration2 + " ms"); |
382 | } |
383 | |
384 | private void runPcm2Lqn(PCMInstance model) { |
385 | |
386 | LqnBuilder lqnBuilder = new LqnBuilder(config.isInfiniteTaskMultiplicity()); |
387 | |
388 | if (getSolverProgramName().equals(FILENAME_LQSIM)){ |
389 | lqnBuilder.setIsLQSimAnalysis(true); |
390 | } |
391 | |
392 | ResourceEnvironment2Lqn reVisitor = new ResourceEnvironment2Lqn( |
393 | lqnBuilder, config); |
394 | reVisitor.doSwitch(model.getResourceEnvironment()); |
395 | |
396 | UsageModel2Lqn umVisitor = new UsageModel2Lqn(lqnBuilder, |
397 | new ContextWrapper(model)); |
398 | umVisitor.doSwitch(model.getUsageModel()); |
399 | |
400 | lqnBuilder.finalizeLqnModel(config); |
401 | |
402 | LqnXmlHandler lqnXmlHandler = new LqnXmlHandler(lqnBuilder |
403 | .getLqnModel()); |
404 | lqnXmlHandler.saveModelToXMI(filenameInputXML); |
405 | |
406 | Pcm2LqnHelper.clearGuidMap(); |
407 | runLqn2Xml(); |
408 | runLqn2XmlReformat(); |
409 | |
410 | } |
411 | |
412 | /** |
413 | * Converts the resulting XML file back to the old LQN file format. |
414 | */ |
415 | private void runLqn2Xml() { |
416 | try { |
417 | |
418 | ProcessBuilder pb = new ProcessBuilder( |
419 | splitToCommandArray(FILENAME_LQN2XML + " -o" + filenameLQN |
420 | + " -Oxml " + filenameInputXML)); |
421 | pb.redirectErrorStream(true); |
422 | // Process proc = Runtime.getRuntime().exec( |
423 | // FILENAME_LQN2XML+" -o" + FILENAME_LQN + |
424 | // " -Oxml " + FILENAME_INPUT_XML); |
425 | |
426 | // StreamGobbler errorGobbler = new StreamGobbler(proc |
427 | // .getErrorStream(), "ERROR"); |
428 | // StreamGobbler outputGobbler = new StreamGobbler(proc |
429 | // .getInputStream(), "OUTPUT"); |
430 | // errorGobbler.start(); |
431 | // outputGobbler.start(); |
432 | |
433 | Process proc = pb.start(); |
434 | |
435 | this.readStream(proc.getInputStream()); |
436 | |
437 | int exitVal = proc.waitFor(); |
438 | proc.destroy(); |
439 | |
440 | if (exitVal == 0) { |
441 | logger.info("lqn2xml terminated sucessfully"); |
442 | } else { |
443 | logger |
444 | .warn("lqn2xml terminated unsuccessfully. Exit value was " |
445 | + exitVal + "."); |
446 | } |
447 | |
448 | } catch (Throwable e) { |
449 | e.printStackTrace(); |
450 | } |
451 | } |
452 | |
453 | /** |
454 | * Performs a reformat of the resulting XML file in order to produce XML |
455 | * which can be processed from lqns. This is done utilizing lqn2xml. Without |
456 | * the reformat lqns don't like the XML file and will probably return an |
457 | * error. |
458 | * <p> |
459 | * The reformatted file will be written to {@link #filenameResultXML}. |
460 | */ |
461 | private void runLqn2XmlReformat() { |
462 | try { |
463 | ProcessBuilder pb = new ProcessBuilder( |
464 | splitToCommandArray(FILENAME_LQN2XML + " -o" |
465 | + filenameResultXML + " -Oxml " + filenameInputXML)); |
466 | pb.redirectErrorStream(true); |
467 | |
468 | // Process proc = Runtime.getRuntime().exec( |
469 | // FILENAME_LQN2XML+" -o" + FILENAME_RESULT_XML + |
470 | // " -Oxml " + FILENAME_INPUT_XML); |
471 | // |
472 | Process proc = pb.start(); |
473 | |
474 | // StreamGobbler errorGobbler = new StreamGobbler(proc |
475 | // .getErrorStream(), "ERROR"); |
476 | // StreamGobbler outputGobbler = new StreamGobbler(proc |
477 | // .getInputStream(), "OUTPUT"); |
478 | // errorGobbler.start(); |
479 | // outputGobbler.start(); |
480 | |
481 | this.readStream(proc.getInputStream()); |
482 | |
483 | int exitVal = proc.waitFor(); |
484 | proc.destroy(); |
485 | |
486 | if (exitVal == 0) { |
487 | logger.info("lqn2xml terminated sucessfully"); |
488 | } else { |
489 | logger |
490 | .warn("lqn2xml terminated unsuccessfully. Exit value was " |
491 | + exitVal + "."); |
492 | } |
493 | } catch (Throwable e) { |
494 | e.printStackTrace(); |
495 | } |
496 | } |
497 | |
498 | private void runDSolver(PCMInstance model) { |
499 | // TODO: fix this (only uses one usage scenario): |
500 | UsageModelVisitor visitor = new UsageModelVisitor(model); |
501 | List<UsageScenario> scenarios = model.getUsageModel() |
502 | .getUsageScenario_UsageModel(); |
503 | for (UsageScenario usageScenario : scenarios) { |
504 | visitor |
505 | .doSwitch(usageScenario |
506 | .getScenarioBehaviour_UsageScenario()); |
507 | } |
508 | } |
509 | |
510 | /** |
511 | * |
512 | * @param is |
513 | * @return the concatenated String of all error messages encountered during the analysis |
514 | */ |
515 | private String readStream(InputStream is) { |
516 | String errorMessages = ""; |
517 | try { |
518 | InputStreamReader isr = new InputStreamReader(is); |
519 | BufferedReader br = new BufferedReader(isr); |
520 | String line = null; |
521 | while ((line = br.readLine()) != null) |
522 | // if (type.equals("ERROR")) logger.error(line); |
523 | if (line.contains("warning")) { |
524 | if (isDebug()) { |
525 | logger.debug(line); |
526 | } |
527 | // else do not log. |
528 | } else { |
529 | logger.warn(line); |
530 | errorMessages += line + "\n"; |
531 | } |
532 | } catch (IOException ioe) { |
533 | ioe.printStackTrace(); |
534 | } |
535 | return errorMessages; |
536 | } |
537 | |
538 | private String[] splitToCommandArray(String command) { |
539 | return command.split("\\s"); |
540 | } |
541 | |
542 | // FIXME: This is not a good way to remove get the debugging statements. Fix |
543 | // this when introducing a better configuration concept here. |
544 | private boolean isDebug() { |
545 | int level = config.getDebugLevel(); |
546 | if (level <= 1) { |
547 | return true; |
548 | } else |
549 | return false; |
550 | |
551 | // case 0: |
552 | // return Level.TRACE; |
553 | // case 1: |
554 | // return Level.DEBUG; |
555 | // case 2: |
556 | // return Level.INFO; |
557 | // case 3: |
558 | // return Level.WARN; |
559 | // case 4: |
560 | // return Level.ERROR; |
561 | // case 5: |
562 | // return Level.ALL; |
563 | // default: |
564 | // return Level.INFO; |
565 | } |
566 | |
567 | } |
568 | |
569 | // TODO: Anne: delete this method and the related comments above if the changes |
570 | // (to use ProcessBuilder and a single threaded reading out of the output) has |
571 | // proved useful. |
572 | @Deprecated |
573 | class StreamGobbler extends Thread { |
574 | |
575 | private static Logger logger = Logger.getLogger(StreamGobbler.class |
576 | .getName()); |
577 | |
578 | InputStream is; |
579 | String type; |
580 | |
581 | StreamGobbler(InputStream is, String type) { |
582 | this.is = is; |
583 | this.type = type; |
584 | } |
585 | |
586 | @Override |
587 | public void run() { |
588 | try { |
589 | InputStreamReader isr = new InputStreamReader(is); |
590 | BufferedReader br = new BufferedReader(isr); |
591 | String line = null; |
592 | while ((line = br.readLine()) != null) |
593 | // if (type.equals("ERROR")) logger.error(line); |
594 | if (line.contains("warning")) { |
595 | logger.debug(line); |
596 | } else { |
597 | logger.warn(line); |
598 | } |
599 | } catch (IOException ioe) { |
600 | ioe.printStackTrace(); |
601 | } |
602 | } |
603 | } |