/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.karaf.shell.commands;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;

import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
import org.apache.felix.gogo.commands.Option;
import org.apache.karaf.shell.console.AbstractAction;

@Command(scope = "shell", name = "tail", description = "Displays the last lines of a file")
public class TailAction extends AbstractAction {

    private static final int DEFAULT_NUMBER_OF_LINES = 10;

    @Option(name = "-n", aliases = {}, description = "The number of lines to display, starting at 1.", required = false, multiValued = false)
    private int numberOfLines;

    @Option(name = "-f", aliases = {}, description = "Follow file changes", required = false, multiValued = false)
    private boolean continuous;

    @Option(name = "-s", aliases = {}, description = "Sleep interval (used for follow)", required = false, multiValued = false)
    private long sleepInterval;

    @Argument(index = 0, name = "path or url", description = "A file path or url to display.", required = false, multiValued = false)
    private String path;

    protected Object doExecute() throws Exception {
        //If no paths provided assume standar input
        if (path == null || path.trim().length() == 0) {
            if (log.isDebugEnabled()) {
                log.debug("Tailing STDIN");
            }
            tail(new BufferedReader(new InputStreamReader(System.in)));
        } else {
            BufferedReader reader;

            // First try a URL
            try {
                URL url = new URL(path);
                if (log.isDebugEnabled()) {
                    log.debug("Tailing URL: " + url);
                }
                reader = new BufferedReader(new InputStreamReader(url.openStream()));
            }
            catch (MalformedURLException ignore) {
                // They try a file
                File file = new File(path);
                if (log.isDebugEnabled()) {
                    log.debug("Tailing file: " + file);
                }
                reader = new BufferedReader(new FileReader(file));
            }

            try {
                tail(reader);
            }
            finally {
                try {
                    reader.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }

        return null;
    }

    /**
     * prints the tail of the file / url
     * 
     * @param reader
     * @throws IOException
     */
    private void tail(final BufferedReader reader) throws IOException {
        
        if (numberOfLines < 1) {
            numberOfLines = DEFAULT_NUMBER_OF_LINES;
        }
        
        LinkedList<String> lines = new LinkedList<String>();
        String line;
        while ((line = reader.readLine()) != null) {
                lines.add(line);
                if (lines.size() > numberOfLines) {
                    lines.removeFirst();
                }
            }

        for (String l : lines) {
            System.out.println(l);
        }

        //If command is running as continuous
        while (continuous) {
            try {
                Thread.sleep(sleepInterval);
                 while ((line = reader.readLine()) != null) {
                   System.out.println(line);
                 }
            } catch (InterruptedException ex) {
                return;
            }
        }
    }
}

@@ -1506,16 +1506,76 @@
  = 10;%0A%0A
+    private static final int DEFAULT_SLEEP_INTERVAL = 200;%0A%0A
     @Opt
@@ -3680,24 +3680,46 @@
 ader) throws
+ InterruptedException,
  IOException
@@ -3713,32 +3713,32 @@
 , IOException %7B%0A
-
         %0A       
@@ -3818,32 +3818,127 @@
 INES;%0A        %7D%0A
+        if (sleepInterval %3C 1) %7B%0A            sleepInterval = DEFAULT_SLEEP_INTERVAL;%0A        %7D%0A
         %0A       
@@ -4073,28 +4073,24 @@
             
-    
 lines.add(li
@@ -4086,36 +4086,32 @@
 ines.add(line);%0A
-    
             if (
@@ -4154,28 +4154,24 @@
             
-    
 lines.remove
@@ -4179,34 +4179,16 @@
 irst();%0A
-                %7D%0A
         
@@ -4184,32 +4184,42 @@
 );%0A            %7D
+%0A        %7D
 %0A%0A        for (S
@@ -4358,38 +4358,16 @@
 uous) %7B%0A
-            try %7B%0A    
         
@@ -4395,29 +4395,24 @@
 pInterval);%0A
-     
             
@@ -4464,35 +4464,32 @@
                 
-   
 System.out.print
@@ -4502,99 +4502,8 @@
 e);%0A
-                 %7D%0A            %7D catch (InterruptedException ex) %7B%0A                return;%0A
     

Fix possible cpu burn