diff -Naur server-orig/src/org/netbeans/api/server/output/FileInputProvider.java server-new/src/org/netbeans/api/server/output/FileInputProvider.java --- server-orig/src/org/netbeans/api/server/output/FileInputProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/FileInputProvider.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,110 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.io.File; +import java.nio.charset.Charset; +import org.openide.util.Parameters; + +/** + * The provider of the file with associated charset. Object returned from + * different invocations of {@link #getFileInput()} can be different. + * + * @author Petr Hejl + */ +public interface FileInputProvider { + + /** + * Returns the current {@link FileInput} to be used by the caller. + * + * @return the current {@link FileInput} to be used by the caller, + * may return null + */ + FileInput getFileInput(); + + /** + * The current {@link File} with the defined {@link Charset}. + * + * This class is Immutable. + */ + public static class FileInput { + + private final File file; + + private final Charset charset; + + /** + * Creates the instance defining the given file object with the given + * charset. + * + * @param file the file itself, must not be null + * @param charset the charset of the file, must not be null + */ + public FileInput(File file, Charset charset) { + Parameters.notNull("file", file); + Parameters.notNull("charset", charset); + + this.file = file; + this.charset = charset; + } + + /** + * Returns the current file. + * + * @return the current file + */ + public final File getFile() { + return file; + } + + /** + * Returns the charset of the current file. + * + * @return the charset of the current file + */ + public final Charset getCharset() { + return charset; + } + + } + +} diff -Naur server-orig/src/org/netbeans/api/server/output/LineProcessor.java server-new/src/org/netbeans/api/server/output/LineProcessor.java --- server-orig/src/org/netbeans/api/server/output/LineProcessor.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/LineProcessor.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,68 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +/** + * Process the lines fetched by {@link LineReader}. + *

+ * When the implementation is used just by single {@link LineReader} it + * does not have to be thread safe. + * + * @author Petr Hejl + * @see LineReader + */ +public interface LineProcessor { + + /** + * Processes the line. One line can be processed multiple times as + * described in {@link LineReader#readLines(LineProcessor, boolean)}. + * + * @param line the line to process, can be null + */ + void processLine(String line); + + /** + * Notifies the processor that it should reset its state. + */ + void reset(); + +} diff -Naur server-orig/src/org/netbeans/api/server/output/LineReader.java server-new/src/org/netbeans/api/server/output/LineReader.java --- server-orig/src/org/netbeans/api/server/output/LineReader.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/LineReader.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,93 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.io.IOException; + +/** + * Fetches and processes the lines with line processor. Note that (depending on + * actual implementation) the same line can be passed to {@link LineProcessor} + * multiple times. + *

+ * The implementation of the {@link #readLines(LineProcessor, boolean)} + * should be interruptible to allow {@link ReaderManager} in which it will + * be used to stop immediately. + *

+ * If the implementation will be used just by single {@link ReaderManager} + * it does not have to be thread safe. + * + * @author Petr Hejl + */ +public interface LineReader { + + /** + * Reads indeterminate number of lines fetched from the source. Passes + * the fetched lines to {@link LineProcessor}. + *

+ * Single line can be sent to the {@link LineProcessor} multiple times. + * Such mutiple processing is always separated by call of the method + * {@link LineProcessor#reset()} (however it is not guaranteed that + * {@link LineProcessor#reset()} is called only in this case). + *

+ * If the line processor is passed exclusively to this processor it does + * not have to be thread safe. + * + * @param lineProcessor processor for lines, null is allowed + * @param allAvailable when set to true all available input + * is fetched, parsed and processed including the remaining + * part (even if the last character is not the line separator) + * @return number of lines read + * @throws IOException if any problem with line fetching occurs + */ + int readLines(LineProcessor lineProcessor, boolean allAvailable) throws IOException; + + /** + * Closes the reader freeing the resources held by it. Behaviour of the + * reader after calling this is not defined. Calling the + * {@link #readLines(LineProcessor, boolean)} after calling this method typically + * leads to {@link java.lang.IllegalStateException}. + * + * @throws IOException if any problem occurs while closing the processor + */ + void close() throws IOException; + +} diff -Naur server-orig/src/org/netbeans/api/server/output/LineReaders.java server-new/src/org/netbeans/api/server/output/LineReaders.java --- server-orig/src/org/netbeans/api/server/output/LineReaders.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/LineReaders.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,117 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.io.File; +import java.io.InputStream; +import java.nio.charset.Charset; +import org.netbeans.modules.server.output.FileLineReader; +import org.netbeans.modules.server.output.StreamLineReader; + +/** + * Factory methods for {@link LineReader}. + * + * @author Petr Hejl + */ +public final class LineReaders { + + private LineReaders() { + super(); + } + + /** + * Creates the {@link LineReader} reading lines from the given stream. + *

+ * It is mainly intended for reading process streams or not growing files. + * Returned {@link LineReader} is not thread safe, but responsive to + * interruption. + * + * @param stream input stream from which the lines will be fetched + * @param charset the charset that will be used to process the lines + * @return the reader backed by the given stream + */ + public static LineReader forStream(InputStream stream, Charset charset) { + return new StreamLineReader(stream, charset); + } + + /** + * Creates the {@link LineReader} reading lines from the given file. + *

+ * Intended for tailing the file. If the file gets shorter than the already + * processed amount of data it is processed again from its beginning. + * Returned {@link LineReader} is not thread safe, but responsive to + * interruption. + * + * @param file the fileObject from which the lines will be fetched + * @param charset the charset that will be used to process the lines + * @return the reader backed by the given fileObject + */ + public static LineReader forFile(File file, Charset charset) { + final FileInputProvider.FileInput fileInput = new FileInputProvider.FileInput(file, charset); + + return new FileLineReader(new FileInputProvider() { + + public FileInput getFileInput() { + return fileInput; + } + + }); + } + + /** + * Creates the {@link LineReader} reading lines from the file provided + * by the given {@link FileInputProvider}. The location or name of the file + * can change during the time. + *

+ * Intended for tailing the file in the case the file name and/or location + * is not stable in time (like rotating log files for example). Returned + * {@link LineReader} is not thread safe, but responsive to interruption. + * + * @param provider the provider of the current file that will be used + * by the {@link LineReader} + * @return the reader fetching the data from the file provided by the provider + */ + public static LineReader forFileInputProvider(FileInputProvider provider) { + return new FileLineReader(provider); + } + +} diff -Naur server-orig/src/org/netbeans/api/server/output/package-info.java server-new/src/org/netbeans/api/server/output/package-info.java --- server-orig/src/org/netbeans/api/server/output/package-info.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/package-info.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +/** + * The support API for processing the growing streams or files. The API + * provides classes for automated processing of such inputs. The processing + * is line based. + * + * @see org.netbeans.api.server.output.ReaderManager + */ +package org.netbeans.api.server.output; + diff -Naur server-orig/src/org/netbeans/api/server/output/PrintingLineProcessor.java server-new/src/org/netbeans/api/server/output/PrintingLineProcessor.java --- server-orig/src/org/netbeans/api/server/output/PrintingLineProcessor.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/PrintingLineProcessor.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.openide.util.Parameters; +import org.openide.windows.OutputWriter; + +/** + * LineProcessor that prints the passed lines to {@link OutputWriter}. + *

+ * This class is not NotThreadSafe. + * + * @author Petr Hejl + */ +public final class PrintingLineProcessor implements LineProcessor { + + private static final Logger LOGGER = Logger.getLogger(PrintingLineProcessor.class.getName()); + + private final OutputWriter out; + + private final boolean resetEnabled; + + /** + * Creates the new processor passing th lines to given writer. + * + * @param out writer to which the lines will be passed + * @param resetEnabled flag indicating whether the reset call should reset + * the writer, true enables resetting + */ + public PrintingLineProcessor(OutputWriter out, boolean resetEnabled) { + Parameters.notNull("out", out); + + this.out = out; + this.resetEnabled = resetEnabled; + } + + /** + * {@inheritDoc} + *

+ * If the line is not null it is printed to writer. + */ + public void processLine(String line) { + // all lines are written to the output pane + if (line != null) { + out.println(line); + } + } + + /** + * {@inheritDoc} + *

+ * If the reset was not enabled (by flag passed to constructor) this is noop. + * Otherwise this call rests the writer. + */ + public void reset() { + if (!resetEnabled) { + return; + } + + try { + out.reset(); + } catch (IOException ex) { + LOGGER.log(Level.INFO, null, ex); + } + } + +} \ No newline at end of file diff -Naur server-orig/src/org/netbeans/api/server/output/ProxyLineProcessor.java server-new/src/org/netbeans/api/server/output/ProxyLineProcessor.java --- server-orig/src/org/netbeans/api/server/output/ProxyLineProcessor.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/ProxyLineProcessor.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,96 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * LineProcessor serving as a proxy for other LineProcessors. + *

+ * This class is Immutable. + * + * @author Petr Hejl + */ +public final class ProxyLineProcessor implements LineProcessor { + + private final List processors = new ArrayList(); + + /** + * Constructs the proxy to the given processors. + * + * @param processors processors to wrap, any null processor is + * ignored + */ + public ProxyLineProcessor(LineProcessor... processors) { + for (LineProcessor processor : processors) { + if (processor != null) { + this.processors.add(processor); + } + } + } + + /** + * {@inheritDoc} + *

+ * Delegates call to the underlying processors. The order is defined by the + * order of processors passed to constructor. + */ + public void processLine(String line) { + for (LineProcessor processor : processors) { + processor.processLine(line); + } + } + + /** + * {@inheritDoc} + *

+ * Delegates call to the underlying processors. The order is defined by the + * order of processors passed to constructor. + */ + public void reset() { + for (LineProcessor processor : processors) { + processor.reset(); + } + } + +} diff -Naur server-orig/src/org/netbeans/api/server/output/ReaderManager.java server-new/src/org/netbeans/api/server/output/ReaderManager.java --- server-orig/src/org/netbeans/api/server/output/ReaderManager.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/ReaderManager.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,221 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.modules.server.output.ReaderThread; +import org.openide.util.Parameters; + +/** + * Manager for reading and processing the lines provided {@link LineReader}s. + *

+ * Note that it is highly recommended to have all used {@link LineReader}s + * responsive to interruption. Otherwise the delay between the {@link #stop()} + * call and actual finish of the processing can be significant. + *

+ * The simple example for processing the stream: + *

+ *

+ *     InputStream is = ...;
+ * Charset charset = ...;
+ * LineProcessor myProcessor = ...;
+ *
+ * ReaderManager manager = ReaderManager.newManager(
+ *     LineReaders.forStream(is, charset), myProcessor);
+ * manager.start();
+ * ...
+ * manager.stop();
+ *
+ *

+ * This class is ThreadSafe. + * + * @author Petr Hejl + */ +public final class ReaderManager { + + static { + ReaderThread.Accessor.DEFAULT = new ReaderThread.Accessor() { + + @Override + public void notifyFinished(ReaderManager manager, ReaderThread thread) { + manager.notifyFinished(thread); + } + }; + } + + private static final Logger LOGGER = Logger.getLogger(ReaderManager.class.getName()); + + private final List threads = new ArrayList(); + + /** GuardedBy("this") */ + private boolean started = false; + + /** GuardedBy("this") */ + private int finishedCount = 0; + + private ReaderManager(Pair... pairs) { + for (int i = 0; i < pairs.length; i++) { + if (pairs[i] != null) { + threads.add(new ReaderThread(this, pairs[i].getReader(), + pairs[i].getProcessor())); + } + } + } + + /** + * Creates the manager managing any amount of {@link LineReader}s with + * the {@link LineProcessor}s associated to them. + * + * @param pairs the pairs of the {@link LineReader}s with the {@link LineProcessor}s + * associated to them + * @return the manager for hadling all given {@link LineReader}s + */ + public static ReaderManager newManager(Pair... pairs) { + return new ReaderManager(pairs); + } + + /** + * Creates the manager managing the single {@link LineReader} with + * corresponding {@link LineProcessor}. + * + * @param lineReader the source of the lines to process, must not be null + * @param lineProcessor representation of custom line processing code, may be null + * @return the manager for handling the given {@link LineReader} + */ + public static ReaderManager newManager(LineReader lineReader, LineProcessor lineProcessor) { + return newManager(new ReaderManager.Pair(lineReader, lineProcessor)); + } + + /** + * Starts the manager. Starts tailing all managed {@link LineReader}s + * and processing the data with associated {@link LineProcessor}s (if any). + *

+ * Calling start on the instance once started has no effect. + */ + public synchronized void start() { + if (started) { + return; + } + + LOGGER.log(Level.FINE, "Starting reader manager"); // NOI18N + + for (ReaderThread thread : threads) { + thread.start(); + } + + started = true; + } + + /** + * Stops the manager. All owned {@link LineReader}s are closed + * through {@link LineReader#close()}. + *

+ * When this method exits it is not guaranteed that processing was already + * finished. Use {@link #isRunning()} to check if it was already finished. + */ + public synchronized void stop() { + LOGGER.log(Level.FINE, "Stopping reader manager"); // NOI18N + + for (ReaderThread thread : threads) { + thread.interrupt(); + } + } + + /** + * Returns false if the manager already finished the processing. + * + * @return false if the manager already finished the processing + */ + public synchronized boolean isRunning() { + return finishedCount < threads.size(); + } + + /** + * Helper method for tests. + * + * @return + */ + List getThreads() { + return Collections.unmodifiableList(threads); + } + + private synchronized void notifyFinished(ReaderThread thread) { + finishedCount++; + } + + /** + * The container class for reader and processor pairs. + */ + public static final class Pair { + + private final LineReader reader; + + private final LineProcessor processor; + + /** + * Creates the new pair of the reader and processor. + * + * @param reader the reader value, must not be null + * @param processor the associated processor, null is allowed + */ + public Pair(LineReader reader, LineProcessor processor) { + Parameters.notNull("reader", reader); + + this.reader = reader; + this.processor = processor; + } + + private LineReader getReader() { + return reader; + } + + private LineProcessor getProcessor() { + return processor; + } + + } + +} diff -Naur server-orig/src/org/netbeans/api/server/output/WaitingLineProcessor.java server-new/src/org/netbeans/api/server/output/WaitingLineProcessor.java --- server-orig/src/org/netbeans/api/server/output/WaitingLineProcessor.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/api/server/output/WaitingLineProcessor.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,126 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.api.server.output; + +import java.util.regex.Pattern; +import org.openide.util.Parameters; + +/** + * LineProcessor implementing barrier for waiting on specific + * pattern matching line. + *

+ * This class is ThreadSafe. + * + * @author Petr Hejl + */ +public final class WaitingLineProcessor implements LineProcessor { + + private final Pattern pattern; + + /** GuardedBy("this") */ + private boolean processed = false; + + /** + * Constructs the processor implementing the the barrier. Barrier is opened + * when it will process the line that matches the pattern. + * + * @param pattern pattern triggering the opening + */ + public WaitingLineProcessor(Pattern pattern) { + Parameters.notNull("pattern", pattern); + + this.pattern = pattern; + } + + /** + * {@inheritDoc} + *

+ * Checks the line for the specified pattern. If the line matches the + * pattern all waiting threads are notified. + */ + public void processLine(String line) { + if (line != null) { + if (pattern.matcher(line).matches()) { + synchronized (this) { + processed = true; + notifyAll(); + } + } + } + } + + /** + * Noop for this processor. + */ + public synchronized void reset() { + + } + + /** + * If the line matching the pattern not yet passed through processor + * the calling thread will be suspended, waiting for this event. Otherwise + * the thread just passes through. + * + * @throws java.lang.InterruptedException if the thread was interrupted + * while waiting + */ + public synchronized void await() throws InterruptedException { + while (!processed) { + wait(); + } + } + + /** + * If the line matching the pattern not yet passed through processor + * the calling thread will be suspended, waiting for this event. + * The waiting period is limited by the timeout value. This method does + * not prevent spurious wakeups. + * + * @param timeout wait timeout in millis + * @throws java.lang.InterruptedException if the thread was interrupted + * while waiting + */ + public synchronized void await(long timeout) throws InterruptedException { + wait(timeout); + } + +} diff -Naur server-orig/src/org/netbeans/modules/server/output/FileLineReader.java server-new/src/org/netbeans/modules/server/output/FileLineReader.java --- server-orig/src/org/netbeans/modules/server/output/FileLineReader.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/modules/server/output/FileLineReader.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.server.output; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.api.server.output.FileInputProvider; +import org.netbeans.api.server.output.LineProcessor; +import org.netbeans.api.server.output.LineReader; +import org.openide.util.Parameters; + +/** + * + * This class is NotThreadSafe. + * @author Petr Hejl + */ +public class FileLineReader implements LineReader { + + private static final Logger LOGGER = Logger.getLogger(FileLineReader.class.getName()); + + private static final int BUFFER_SIZE = 128; + + private final LineParsingHelper helper = new LineParsingHelper(); + + private final FileInputProvider fileProvider; + + private final ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); + + private FileInputProvider.FileInput currentFile; + + private ReadableByteChannel channel; + + private long fileLength; + + private boolean closed; + + public FileLineReader(FileInputProvider fileProvider) { + Parameters.notNull("fileProvider", fileProvider); + + this.fileProvider = fileProvider; + } + + public int readLines(LineProcessor lineProcessor, boolean allAvailable) { + if (closed) { + throw new IllegalStateException("Already closed reader"); + } + + int fetched = 0; + try { + FileInputProvider.FileInput file = fileProvider.getFileInput(); + + if ((currentFile != file && (currentFile == null || !currentFile.equals(file))) + || fileLength > currentFile.getFile().length() || channel == null) { + + if (channel != null) { + channel.close(); + } + + currentFile = file; + + if (currentFile != null && currentFile.getFile().exists() + && currentFile.getFile().canRead()) { + + channel = Channels.newChannel( + new FileInputStream(currentFile.getFile())); + } + if (fileLength > 0) { + lineProcessor.reset(); + } + fileLength = 0; + // TODO trailing line flush (?) + } + + if (channel == null) { + return fetched; + } + + buffer.clear(); + int size = channel.read(buffer); + if (size > 0) { + fileLength += size; + buffer.position(0).limit(size); + String[] lines = helper.parse(buffer, currentFile.getCharset()); + fetched += lines.length; + + if (lineProcessor != null) { + for (String line : lines) { + lineProcessor.processLine(line); + } + } + } + } catch (IOException ex) { + LOGGER.log(Level.INFO, null, ex); + // we will try the next loop (if any) + if (channel != null) { + try { + channel.close(); + } catch (IOException iex) { + LOGGER.log(Level.FINE, null, ex); + } + } + } + + if (allAvailable) { + String line = helper.getTrailingLine(true); + if (line != null) { + if (lineProcessor != null) { + lineProcessor.processLine(line); + } + fetched += 1; + } + } + return fetched; + } + + public void close() throws IOException { + closed = true; + if (channel != null) { + channel.close(); + channel = null; + } + } + +} diff -Naur server-orig/src/org/netbeans/modules/server/output/LineParsingHelper.java server-new/src/org/netbeans/modules/server/output/LineParsingHelper.java --- server-orig/src/org/netbeans/modules/server/output/LineParsingHelper.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/modules/server/output/LineParsingHelper.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.server.output; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * + * This class is NotThreadSafe. + * @author Petr Hejl + */ +public final class LineParsingHelper { + + private String trailingLine; + + public LineParsingHelper() { + super(); + } + + public String[] parse(byte[] buffer, Charset charset) { + return parse(buffer, 0, buffer.length, charset); + } + + public String[] parse(byte[] buffer, int offset, int limit, Charset charset) { + return parse(charset.decode(ByteBuffer.wrap(buffer, offset, limit))); + } + + public String[] parse(ByteBuffer buffer, Charset charset) { + return parse(charset.decode(buffer)); + } + + public String[] parse(char[] buffer) { + return parse(buffer, 0, buffer.length); + } + + public String[] parse(char[] buffer, int offset, int limit) { + return parse(CharBuffer.wrap(buffer, offset, limit)); + } + + public String[] parse(CharSequence input) { + //prepend the text from the last reading to the text actually read + String lines = (trailingLine != null ? trailingLine : ""); + lines += input.toString(); + int tlLength = (trailingLine != null ? trailingLine.length() : 0); + int start = 0; + List ret = new ArrayList(); + for (int i = 0; i < input.length(); i++) { // going through the text read and searching for the new line + //we see '\n' or '\r', *not* '\r\n' + if (input.charAt(i) == '\r' + && (i + 1 == input.length() || input.charAt(i + 1) != '\n') + || input.charAt(i) == '\n') { + String line = lines.substring(start, tlLength + i); + //move start to the character right after the new line + start = tlLength + (i + 1); + ret.add(line); + } else if (input.charAt(i) == '\r' + && (i + 1 < input.length()) && input.charAt(i + 1) == '\n') {//we see '\r\n' + String line = lines.substring(start, tlLength + i); + //skip the '\n' character + i += 1; + //move start to the character right after the new line + start = tlLength + (i + 1); + ret.add(line); + } + } + if (start < lines.length()) { + //new line was not found at the end of the input, the remaing text is stored for the next reading + trailingLine = lines.substring(start); + } else { + //null and not empty string to indicate that there is no valid input to write out; + //an empty string means that a new line character may be written out according + //to the LineProcessor implementation + trailingLine = null; + } + return ret.toArray(new String[ret.size()]); + } + + public String getTrailingLine(boolean flush) { + String line = trailingLine; + if (flush) { + trailingLine = null; + } + return line; + } +} diff -Naur server-orig/src/org/netbeans/modules/server/output/package-info.java server-new/src/org/netbeans/modules/server/output/package-info.java --- server-orig/src/org/netbeans/modules/server/output/package-info.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/modules/server/output/package-info.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +/** + * Define package level comments. + */ +package org.netbeans.modules.server.output; + diff -Naur server-orig/src/org/netbeans/modules/server/output/ReaderThread.java server-new/src/org/netbeans/modules/server/output/ReaderThread.java --- server-orig/src/org/netbeans/modules/server/output/ReaderThread.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/modules/server/output/ReaderThread.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,159 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.server.output; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.api.server.output.LineProcessor; +import org.netbeans.api.server.output.LineReader; +import org.netbeans.api.server.output.ReaderManager; +import org.openide.util.Parameters; + +/** + * + * This class is ThreadSafe. + * @author Petr Hejl + */ +public class ReaderThread extends Thread { + + private static final Logger LOGGER = Logger.getLogger(ReaderThread.class.getName()); + + private static final int DELAY = 500; + + private static final AtomicLong THREAD_COUNTER = new AtomicLong(0); + + private final ReaderManager readerManager; + + private final LineReader lineReader; + + private final LineProcessor lineProcessor; + + public ReaderThread(ReaderManager readerManager, LineReader lineReader) { + this(readerManager, lineReader, null); + } + + public ReaderThread(ReaderManager readerManager, LineReader lineReader, + LineProcessor lineProcessor) { + + super("line_reader_thread_" + THREAD_COUNTER.incrementAndGet()); // NOI18N + + Parameters.notNull("readerManager", readerManager); + Parameters.notNull("lineReader", lineReader); + + this.setDaemon(true); + this.readerManager = readerManager; + this.lineReader = lineReader; + this.lineProcessor = lineProcessor; + } + + @Override + public void run() { + boolean interrupted = false; + try { + while (true) { + if (Thread.interrupted()) { + interrupted = true; + break; + } + + lineReader.readLines(lineProcessor, false); + + try { + // give the producer some time to write the output + Thread.sleep(DELAY); + } catch (InterruptedException e) { + interrupted = true; + break; + } + } + + lineReader.readLines(lineProcessor, true); + } catch (Exception ex) { + if (!interrupted && !Thread.currentThread().isInterrupted()) { + LOGGER.log(Level.INFO, null, ex); + } + } finally { + // perform cleanup + try { + lineReader.close(); + } catch (IOException ex) { + LOGGER.log(Level.INFO, null, ex); + } finally { + Accessor.DEFAULT.notifyFinished(readerManager, this); + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + } + + /** + * The accessor pattern class. + */ + public abstract static class Accessor { + + /** The default accessor. */ + public static Accessor DEFAULT; + + static { + // invokes static initializer of ReaderManager.class + // that will assign value to the DEFAULT field above + Class c = ReaderManager.class; + try { + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException ex) { + assert false : ex; + } + } + + /** + * Accessor to notify the manager about finished thread. + * + * @param manager the manager to notify + * @param thread the thread that was finished + */ + public abstract void notifyFinished(ReaderManager manager, ReaderThread thread); + + } +} \ No newline at end of file diff -Naur server-orig/src/org/netbeans/modules/server/output/StreamLineReader.java server-new/src/org/netbeans/modules/server/output/StreamLineReader.java --- server-orig/src/org/netbeans/modules/server/output/StreamLineReader.java 1970-01-01 01:00:00.000000000 +0100 +++ server-new/src/org/netbeans/modules/server/output/StreamLineReader.java 2008-02-01 10:53:11.000000000 +0100 @@ -0,0 +1,123 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.server.output; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.Charset; +import java.util.logging.Logger; +import org.netbeans.api.server.output.LineProcessor; +import org.netbeans.api.server.output.LineReader; +import org.openide.util.Parameters; + +/** + * + * This class is NotThreadSafe. + * @author Petr.Hejl + */ +public class StreamLineReader implements LineReader { + + private static final Logger LOGGER = Logger.getLogger(StreamLineReader.class.getName()); + + private static final int BUFFER_SIZE = 128; + + private final LineParsingHelper helper = new LineParsingHelper(); + + private final Charset charset; + + private final ReadableByteChannel channel; + + private final ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); + + private boolean closed; + + public StreamLineReader(InputStream stream, Charset charset) { + Parameters.notNull("stream", stream); + Parameters.notNull("charset", charset); + + this.charset = charset; + this.channel = Channels.newChannel(stream); + } + + public int readLines(LineProcessor lineProcessor, boolean allAvailable) throws IOException { + if (closed) { + throw new IllegalStateException("Already closed reader"); + } + + int fetched = 0; + + buffer.clear(); + int size = channel.read(buffer); + if (size > 0) { + buffer.position(0).limit(size); + String[] lines = helper.parse(buffer, charset); + fetched += lines.length; + + if (lineProcessor != null) { + for (String line : lines) { + lineProcessor.processLine(line); + } + } + } + + if (allAvailable) { + String line = helper.getTrailingLine(true); + if (line != null) { + if (lineProcessor != null) { + lineProcessor.processLine(line); + } + fetched += 1; + } + } + + return fetched; + } + + public void close() throws IOException { + closed = true; + channel.close(); + } + +}