diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/ExecutionDescriptor.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/ExecutionDescriptor.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/ExecutionDescriptor.java Thu Oct 30 15:52:07 2008 +0100 @@ -253,9 +253,10 @@ * processor. The factory is used by {@link ExecutionService} to create * additional processor for standard output. *

- * Note that {@link ExecutionService} always automatically uses + * Note that {@link ExecutionService} automatically uses * the printing processor created by - * {@link org.netbeans.modules.extexecution.api.input.InputProcessors#printing(org.openide.windows.OutputWriter, org.netbeans.modules.extexecution.api.print.LineConvertor, boolean)}. + * {@link org.netbeans.modules.extexecution.api.input.InputProcessors#printing(org.openide.windows.OutputWriter, org.netbeans.modules.extexecution.api.print.LineConvertor, boolean)} + * if there is no configured factory. *

* The default (not configured) value is null. *

@@ -281,9 +282,10 @@ * processor. The factory is used by {@link ExecutionService} to create * additional processor for standard error output. *

- * Note that {@link ExecutionService} always automatically uses + * Note that {@link ExecutionService} automatically uses * the printing processor created by - * {@link org.netbeans.modules.extexecution.api.input.InputProcessors#printing(org.openide.windows.OutputWriter, org.netbeans.modules.extexecution.api.print.LineConvertor, boolean)}. + * {@link org.netbeans.modules.extexecution.api.input.InputProcessors#printing(org.openide.windows.OutputWriter, org.netbeans.modules.extexecution.api.print.LineConvertor, boolean)} + * if there is no configured factory. *

* The default (not configured) value is null. *

@@ -493,9 +495,11 @@ /** * Creates and returns new input processor. * + * @param defaultProcessor default processor created by + * infrastructure that is printing chars to the output window * @return new input processor */ - InputProcessor newInputProcessor(); + InputProcessor newInputProcessor(InputProcessor defaultProcessor); } diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/ExecutionService.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/ExecutionService.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/ExecutionService.java Thu Oct 30 15:52:07 2008 +0100 @@ -533,13 +533,12 @@ private InputProcessor createOutProcessor(OutputWriter writer) { LineConvertorFactory convertorFactory = descriptor.getOutConvertorFactory(); - InputProcessor outProcessor = InputProcessors.ansiStripping( - InputProcessors.printing(writer, - convertorFactory != null ? convertorFactory.newLineConvertor() : null, true)); + InputProcessor outProcessor = InputProcessors.printing(writer, + convertorFactory != null ? convertorFactory.newLineConvertor() : null, true); InputProcessorFactory descriptorOutFactory = descriptor.getOutProcessorFactory(); if (descriptorOutFactory != null) { - outProcessor = InputProcessors.proxy(outProcessor, descriptorOutFactory.newInputProcessor()); + outProcessor = descriptorOutFactory.newInputProcessor(outProcessor); } return outProcessor; @@ -547,13 +546,12 @@ private InputProcessor createErrProcessor(OutputWriter writer) { LineConvertorFactory convertorFactory = descriptor.getErrConvertorFactory(); - InputProcessor errProcessor = InputProcessors.ansiStripping( - InputProcessors.printing(writer, - convertorFactory != null ? convertorFactory.newLineConvertor() : null, false)); + InputProcessor errProcessor = InputProcessors.printing(writer, + convertorFactory != null ? convertorFactory.newLineConvertor() : null, false); InputProcessorFactory descriptorErrFactory = descriptor.getErrProcessorFactory(); if (descriptorErrFactory != null) { - errProcessor = InputProcessors.proxy(errProcessor, descriptorErrFactory.newInputProcessor()); + errProcessor = descriptorErrFactory.newInputProcessor(errProcessor); } return errProcessor; diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/input/InputProcessors.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/input/InputProcessors.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/input/InputProcessors.java Thu Oct 30 15:52:07 2008 +0100 @@ -136,7 +136,8 @@ /** * Returns the processor converting whole lines with convertor and * printing the result including unterminated tail (if present) to the - * given output writer. + * given output writer. If the covertor does not handle line passed to it + * (returning null) raw lines are printed. *

* Reset action on the returned processor resets the writer if it is enabled * by passing true as resetEnabled. Processor @@ -345,7 +346,13 @@ return; } - for (ConvertedLine converted : convertor.convert(line)) { + List convertedLines = convertor.convert(line); + if (convertedLines == null) { + out.println(line); + return; + } + + for (ConvertedLine converted : convertedLines) { if (converted.getListener() == null) { out.println(converted.getText()); } else { diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/input/LineProcessors.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/input/LineProcessors.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/input/LineProcessors.java Thu Oct 30 15:52:07 2008 +0100 @@ -104,7 +104,9 @@ /** * Returns the processor converting lines with convertor and - * printing the result to the given output writer. + * printing the result to the given output writer. If the covertor does + * not handle line passed to it (returning null) raw + * lines are printed. *

* Reset action on the returned processor resets the writer if it is enabled * by passing true as resetEnabled. Processor @@ -213,17 +215,22 @@ LOGGER.log(Level.FINEST, line); if (convertor != null) { - for (ConvertedLine converted : convertor.convert(line)) { - if (converted.getListener() == null) { - out.println(converted.getText()); - } else { - try { - out.println(converted.getText(), converted.getListener()); - } catch (IOException ex) { - LOGGER.log(Level.INFO, null, ex); + List convertedLines = convertor.convert(line); + if (convertedLines != null) { + for (ConvertedLine converted : convertedLines) { + if (converted.getListener() == null) { out.println(converted.getText()); + } else { + try { + out.println(converted.getText(), converted.getListener()); + } catch (IOException ex) { + LOGGER.log(Level.INFO, null, ex); + out.println(converted.getText()); + } } } + } else { + out.println(line); } } else { out.println(line); diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/print/ConvertedLine.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/print/ConvertedLine.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/print/ConvertedLine.java Thu Oct 30 15:52:07 2008 +0100 @@ -39,6 +39,7 @@ package org.netbeans.modules.extexecution.api.print; +import org.openide.util.Parameters; import org.openide.windows.OutputListener; /** @@ -47,14 +48,40 @@ * * @author Petr Hejl */ -public interface ConvertedLine { +public final class ConvertedLine { + + private final String text; + + private final OutputListener listener; + + private ConvertedLine(String text, OutputListener listener) { + assert text != null; + + this.text = text; + this.listener = listener; + } + + /** + * Returns the converted line presenting the given text and with the given + * listener registered when it is diplayed. + * + * @param text line text + * @param listener line listener to register, may be null + * @return converted line + */ + public static ConvertedLine forText(String text, OutputListener listener) { + Parameters.notNull("text", text); + return new ConvertedLine(text, listener); + } /** * Returns the text to display. * * @return the text to display */ - String getText(); + public String getText() { + return text; + } /** * Returns the corresponding listener for actions taken on the line @@ -63,6 +90,8 @@ * @return the corresponding listener for actions taken on the line * or null */ - OutputListener getListener(); + public OutputListener getListener() { + return listener; + } } diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertor.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertor.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertor.java Thu Oct 30 15:52:07 2008 +0100 @@ -53,8 +53,9 @@ /** * Converts the line to lines for output window. Method may return - * no line or any other number of lines for single input line, however it - * must not return null. + * no line or any other number of lines for single input line. If + * the method returns null the line was not handled by the + * convertor. * * @param line input line to convert * @return converted lines for output window diff -r 2532d50dca21 extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertors.java --- a/extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertors.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/src/org/netbeans/modules/extexecution/api/print/LineConvertors.java Thu Oct 30 15:52:07 2008 +0100 @@ -41,6 +41,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -68,6 +69,26 @@ } /** + * Returns the convertor that will delegate to passed converters. + *

+ * On call to {@link LineConvertor#convert(java.lang.String)} converters + * are asked one by one for conversion in the same order they were + * passed to constructor. The first non null value + * is returned. If all coverters return null for particular + * line null is returned. + *

+ * Returned convertor is not thread safe. + * + * @param convertors convertors that will be proxied; the same order + * is used on {@link LineConvertor#convert(java.lang.String)} + * invocation + * @return the convertor proxying passed convertors + */ + public static LineConvertor proxy(LineConvertor... convertors) { + return new ProxyLineConvertor(convertors); + } + + /** * Returns the convertor searching for lines matching the patterns, * considering matched lines as being files. *

@@ -84,9 +105,8 @@ * will use value 1 as a line number. *

* When the line does not match the linePattern or - * received filename does not match filePattern the work is - * delegated to chain convertor. If this convertor is - * null the line containing just the original text is returned. + * received filename does not match filePattern + * null is returned. *

* Resulting converted line contains the original text and a listener * that consults the fileLocator (if any) when clicked @@ -97,8 +117,6 @@ *

* Returned convertor is not thread safe. * - * @param chain the converter to which the line will be passed when it is - * not recognized as file; may be null * @param fileLocator locator that is consulted for real file; used in * listener for the converted line; may be null * @param linePattern pattern for matching the line @@ -111,15 +129,15 @@ * @return the convertor searching for lines matching the patterns, * considering matched lines as being files (names or paths) */ - public static LineConvertor filePattern(LineConvertor chain, FileLocator fileLocator, - Pattern linePattern, Pattern filePattern, int fileGroup, int lineGroup) { + public static LineConvertor filePattern(FileLocator fileLocator, Pattern linePattern, + Pattern filePattern, int fileGroup, int lineGroup) { Parameters.notNull("linePattern", linePattern); if (fileGroup < 0) { throw new IllegalArgumentException("File goup must be non negative: " + fileGroup); // NOI18N } - return new FilePatternConvertor(chain, fileLocator, linePattern, filePattern, fileGroup, lineGroup); + return new FilePatternConvertor(fileLocator, linePattern, filePattern, fileGroup, lineGroup); } /** @@ -130,18 +148,15 @@ * line and listener opening browser with recognized url on click. *

* If line is not recognized as http or https - * URL it is passed to the given chaining convertor. If chaining convertor - * does not exist only the line containing the original text is returned. + * URL null is returned. *

* Returned convertor is not thread safe. * - * @param chain the converter to which the line will be passed when it is - * not recognized as URL; may be null * @return the convertor parsing the line and searching for * http or https URL */ - public static LineConvertor httpUrl(LineConvertor chain) { - return new HttpUrlConvertor(chain); + public static LineConvertor httpUrl() { + return new HttpUrlConvertor(); } /** @@ -163,16 +178,31 @@ } - private static List chain(LineConvertor chain, String line) { - if (chain != null) { - return chain.convert(line); + private static class ProxyLineConvertor implements LineConvertor { + + private final List convertors = new ArrayList(); + + public ProxyLineConvertor(LineConvertor... convertors) { + for (LineConvertor convertor : convertors) { + if (convertor != null) { + this.convertors.add(convertor); + } + } } - return Collections.singletonList(new SimpleConvertedLine(line)); + public List convert(String line) { + for (LineConvertor convertor : convertors) { + List converted = convertor.convert(line); + if (converted != null) { + return converted; + } + } + + return null; + } + } private static class FilePatternConvertor implements LineConvertor { - - private final LineConvertor chain; private final FileLocator locator; @@ -184,15 +214,14 @@ private final int lineGroup; - public FilePatternConvertor(LineConvertor chain, FileLocator locator, - Pattern linePattern, Pattern filePattern) { - this(chain, locator, linePattern, filePattern, 1, 2); + public FilePatternConvertor(FileLocator locator, Pattern linePattern, + Pattern filePattern) { + this(locator, linePattern, filePattern, 1, 2); } - public FilePatternConvertor(LineConvertor chain, FileLocator locator, - Pattern linePattern, Pattern filePattern, int fileGroup, int lineGroup) { + public FilePatternConvertor(FileLocator locator, Pattern linePattern, + Pattern filePattern, int fileGroup, int lineGroup) { - this.chain = chain; this.locator = locator; this.linePattern = linePattern; this.fileGroup = fileGroup; @@ -204,7 +233,7 @@ // Don't try to match lines that are too long - the java.util.regex library // throws stack exceptions (101234) if (line.length() > 400) { - return chain(chain, line); + return null; } Matcher match = linePattern.matcher(line); @@ -224,7 +253,7 @@ file = file.substring(2); } if (filePattern != null && !filePattern.matcher(file).matches()) { - return chain(chain, line); + return null; } } @@ -240,21 +269,19 @@ } return Collections.singletonList( - new SimpleConvertedLine(line, new FindFileListener(file, lineno, locator))); + ConvertedLine.forText(line, new FindFileListener(file, lineno, locator))); } - return chain(chain, line); + return null; } } private static class HttpUrlConvertor implements LineConvertor { - private final LineConvertor chain; - private final Pattern pattern = Pattern.compile(".*(((http)|(https))://\\S+)(\\s.*|$)"); // NOI18N - public HttpUrlConvertor(LineConvertor chain) { - this.chain = chain; + public HttpUrlConvertor() { + super(); } public List convert(String line) { @@ -264,39 +291,15 @@ try { URL url = new URL(stringUrl); return Collections.singletonList( - new SimpleConvertedLine(line, new UrlOutputListener(url))); + ConvertedLine.forText(line, new UrlOutputListener(url))); } catch (MalformedURLException ex) { - // retur chain + // return null } } - return chain(chain, line); + return null; } - } - - private static class SimpleConvertedLine implements ConvertedLine { - - private final String text; - - private final OutputListener listner; - - public SimpleConvertedLine(String text) { - this(text, null); - } - - public SimpleConvertedLine(String text, OutputListener listner) { - this.text = text; - this.listner = listner; - } - - public OutputListener getListener() { - return listner; - } - - public String getText() { - return text; - } } private static class UrlOutputListener implements OutputListener { diff -r 2532d50dca21 extexecution/test/unit/src/org/netbeans/modules/extexecution/api/print/LineConvertorsTest.java --- a/extexecution/test/unit/src/org/netbeans/modules/extexecution/api/print/LineConvertorsTest.java Wed Oct 29 21:34:37 2008 +0100 +++ b/extexecution/test/unit/src/org/netbeans/modules/extexecution/api/print/LineConvertorsTest.java Thu Oct 30 15:52:07 2008 +0100 @@ -47,6 +47,7 @@ import org.openide.filesystems.FileObject; import org.openide.windows.InputOutput; import org.openide.windows.OutputEvent; +import org.openide.windows.OutputListener; /** * @@ -58,38 +59,71 @@ super(name); } + public void testProxy() { + LineConvertor convertor1 = new LineConvertor() { + public List convert(String line) { + if ("line1".equals(line)) { + return Collections.singletonList( + ConvertedLine.forText("converted:" + line, null)); + } + return null; + } + }; + LineConvertor convertor2 = new LineConvertor() { + public List convert(String line) { + if ("line2".equals(line)) { + return Collections.singletonList( + ConvertedLine.forText("converted:" + line, null)); + } + return null; + } + }; + + LineConvertor convertor = LineConvertors.proxy(convertor1, convertor2); + List convertedLines1 = convertor.convert("line1"); + List convertedLines2 = convertor.convert("line2"); + + assertEquals(1, convertedLines1.size()); + assertEquals(1, convertedLines2.size()); + + assertEquals("converted:line1", convertedLines1.get(0).getText()); + assertEquals("converted:line2", convertedLines2.get(0).getText()); + + assertNull(convertor.convert("line3")); + } + public void testFilePattern() { TestConvertor fallback = new TestConvertor(); - LineConvertor convertor = LineConvertors.filePattern(fallback, - null, Pattern.compile("myline:\\s*(myfile\\w*\\.\\w{3})\\s.*"), null, 1, -1); - + LineConvertor convertor = LineConvertors.proxy(LineConvertors.filePattern( + null, Pattern.compile("myline:\\s*(myfile\\w*\\.\\w{3})\\s.*"), null, 1, -1), fallback); + List lines = new ArrayList(); lines.addAll(convertor.convert("otherline: something.txt")); lines.addAll(convertor.convert("myline: myfile01.txt other stuff")); lines.addAll(convertor.convert("total mess")); lines.addAll(convertor.convert("myline: myfile02.txt other stuff")); lines.addAll(convertor.convert("otherline: http://www.netbeans.org")); - + List ignored = new ArrayList(); Collections.addAll(ignored, "otherline: something.txt", "total mess", "otherline: http://www.netbeans.org"); assertEquals(ignored, fallback.getLines()); - + assertEquals(2, lines.size()); assertEquals("myline: myfile01.txt other stuff", lines.get(0).getText()); assertEquals("myline: myfile02.txt other stuff", lines.get(1).getText()); for (ConvertedLine line : lines) { assertNotNull(line.getListener()); - } + } } public void testFilePatternWithFilePattern() { TestConvertor fallback = new TestConvertor(); - LineConvertor convertor = LineConvertors.filePattern(fallback, + LineConvertor convertor = LineConvertors.proxy(LineConvertors.filePattern( null, Pattern.compile("myline:\\s*(myfile\\w*\\.\\w{3})\\s.*"), - Pattern.compile("myfile01\\.\\w{3}"), 1, -1); - + Pattern.compile("myfile01\\.\\w{3}"), 1, -1), fallback); + List lines = new ArrayList(); lines.addAll(convertor.convert("otherline: something.txt")); lines.addAll(convertor.convert("myline: myfile01.txt other stuff")); @@ -97,32 +131,32 @@ lines.addAll(convertor.convert("myline: myfile02.txt other stuff")); lines.addAll(convertor.convert("otherline: http://www.netbeans.org")); lines.addAll(convertor.convert("myline: myfile01.txt specific")); - + List ignored = new ArrayList(); Collections.addAll(ignored, "otherline: something.txt", "total mess", "myline: myfile02.txt other stuff", "otherline: http://www.netbeans.org"); assertEquals(ignored, fallback.getLines()); - + assertEquals(2, lines.size()); assertEquals("myline: myfile01.txt other stuff", lines.get(0).getText()); assertEquals("myline: myfile01.txt specific", lines.get(1).getText()); for (ConvertedLine line : lines) { assertNotNull(line.getListener()); - } + } } - + public void testFilePatternWithLocator() { TestConvertor fallback = new TestConvertor(); TestFileLocator locator = new TestFileLocator(); - LineConvertor convertor = LineConvertors.filePattern(fallback, - locator, Pattern.compile("myline:\\s*(myfile\\w*\\.\\w{3})\\s.*"), null, 1, -1); - + LineConvertor convertor = LineConvertors.proxy(LineConvertors.filePattern( + locator, Pattern.compile("myline:\\s*(myfile\\w*\\.\\w{3})\\s.*"), null, 1, -1), fallback); + List lines = new ArrayList(); lines.addAll(convertor.convert("myline: myfile01.txt other stuff")); lines.addAll(convertor.convert("myline: myfile02.txt other stuff")); - + assertEquals(2, lines.size()); assertEquals("myline: myfile01.txt other stuff", lines.get(0).getText()); assertEquals("myline: myfile02.txt other stuff", lines.get(1).getText()); @@ -135,15 +169,15 @@ } }); } - + List paths = new ArrayList(); - Collections.addAll(paths, "myfile01.txt", "myfile02.txt"); + Collections.addAll(paths, "myfile01.txt", "myfile02.txt"); assertEquals(paths, locator.getPaths()); } public void testHttpUrl() { TestConvertor fallback = new TestConvertor(); - LineConvertor convertor = LineConvertors.httpUrl(fallback); + LineConvertor convertor = LineConvertors.proxy(LineConvertors.httpUrl(), fallback); List lines = new ArrayList(); lines.addAll(convertor.convert("nourl1")); @@ -185,9 +219,9 @@ return lines; } } - + private static class TestFileLocator implements LineConvertors.FileLocator { - + private final List paths = new ArrayList(); public FileObject find(String filename) { @@ -199,4 +233,5 @@ return paths; } } + }