0

I have written a java desktop application that accepts http requests using embedded NanoHTTPD web server https://github.com/NanoHttpd/nanohttpd, after receiving http request my desktop application makes some activity and keeps writing to log text file while executing its job, currently client opening the web page has to wait until the whole job is finished and the whole page is sent and log file is viewed, I would like the log data to be sent to client as soon as they are added to the local log file , I know this is done using ajax but I don't have time to learn it yet, simply how to make updates to some object in java reflect directly to the web page without need to send the whole page.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;

import common.Logging;
import common.TextFiles;
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.ServerRunner;
import fi.iki.elonen.SimpleWebServer;

public class TestServer  extends NanoHTTPD {
  static boolean isDoingAJob=false;
  public TestServer() {
    super(8080);
  }


    @Override public Response serve(IHTTPSession session) {
      Method method = session.getMethod();
      Map<String,String> params = session.getParms();
      String uri = session.getUri();
      System.out.println(method + " '" + uri + "' ");
      String msg = "<html><style>h1 {  color: green;  background-color: black;}p {  color: gray;          background-color: black;}div {  color: gray;  background-color: black;}body { color: gray; background-color: black;}</style><body><h1>Remote Test Service</h1>";
      Map<String, String> parms = session.getParms();
      for(String paramKey:parms.keySet()){
          String job=params.get(paramKey);

          msg+="Status: "+(isDoingAJob?"Waited in queue.":"Immediate run.");
          if ("tcl".equalsIgnoreCase(paramKey)){
              try {
                  //if another request is being executed wait until finished
                  while(isDoingAJob){
                    Thread.sleep(3000);
                  }
                //Raise a flag while executing a test run
                isDoingAJob=true;
                SomeJobClass.doSomeWork(job.split(" "));
                isDoingAJob=false;
                ArrayList<String> lines=TextFiles.load(Logging.getLogFile().toString());
                for(String line: lines){
                    msg+="<p>"+line+"</p>";
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else{
            //echo help if parameter key is not tcl
            ArrayList<String> lines=TextFiles.load("some help.txt");
            for(String line: lines){
                msg+="<p>"+line+"</p>";
            }
        }
    }

    //show this when no parameters passed
    if (parms.isEmpty()){
        ArrayList<String> lines=TextFiles.load("some help.txt");
        for(String line: lines){
            msg+="<p>"+line+"</p>";
        }
    }
    msg += "</body></html>";
    return new NanoHTTPD.Response(msg);
   }


    public static void main(String[] args) {
       ServerRunner.run(TestServer.class);
    }
}

I found this code http://www.binpress.com/app/jquery-log-viewer/570 but didn't work for me

<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="jquery.logviewer.js"></script>
<script type="text/javascript">

jQuery(document).bind("ready", function() {
 jQuery('#logcontent').logViewer({logUrl: 'log.html'});
});
</script>
</head>
<body>
Live log:<br/>
<textarea id="logcontent" autocomplete="off">
Amr Lotfy
  • 2,937
  • 5
  • 36
  • 56
  • Need a little more explanation there.. I am confused.. webpage? java desktop app? does the desktop app read the log file and send it via nanohttpd to a webpage? – sethu Sep 23 '14 at 08:43
  • @sethu yes, I added more details. – Amr Lotfy Sep 23 '14 at 11:25

2 Answers2

1

The easiest way to do this would be as below:

package fi.iki.elonen;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class Stackoverflowtest extends NanoHTTPD{
    static boolean isDoingAJob=false;
    public Stackoverflowtest() {
        super(8080);
    }


    @Override public Response serve(IHTTPSession session) {
        Method method = session.getMethod();
        Map<String,String> params = session.getParms();
        String uri = session.getUri();
        System.out.println(method + " '" + uri + "' ");
    String msg = "<html><style>h1 {  color: green;  background-color: black;}p {  color: gray;          background-color: black;}div {  color: gray;      background-color: black;}body { color: gray; background-color: black;}</style><body><h1>Remote Test Service</h1>";
        try {
            List<String> lines= FileUtils.readLines(new File("<fileloc>"));
            for(String line: lines){
                msg+="<p>"+line+"</p>";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        msg += "</body><script>setTimeout(function(){\n" +
                "   window.location.reload(1);\n" +
                "}, 5000);</script></html>";
        return new NanoHTTPD.Response(msg);
    }


    public static void main(String[] args) {
        try {
            new Stackoverflowtest().start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Notice the script at the bottom. It just makes the browser reload every 5s. You don't need ajax or anything, for a simplistic solution. If you want to build something more sophisticated like getting only the newly added lines to the browser, then the solution will need to change a bit.

Note: For this to work, in the NanoHTTPD class, in the run() method, I changed the myThread.setDeamon(true) to false. Otherwise you will need to make your main thread sleep for a long time. Else the program will just exit.

sethu
  • 8,181
  • 7
  • 39
  • 65
  • Nice work! the problem is refreshing the page periodically will resend same http request to the server which in my case causes a new job (same as last one) to be executed, besides on a long log file i think it will make UI glitches. – Amr Lotfy Sep 24 '14 at 14:40
  • 1
    True. You will need to recode the serve() method to take care of that. :) But I hope it gets you started. – sethu Sep 24 '14 at 14:49
1

Successfully got it working, it is by jquery

server

public class TestServer  extends NanoHTTPD {

public static boolean isTesting=false;
public TestServer() {
    super(8080);
}
@Override public Response serve(IHTTPSession session) {
    Method method = session.getMethod();
    Map<String,String> params = session.getParms();
    String uri = session.getUri();
    if (uri.length()>1){
        //remove the starting /
        uri=uri.substring(1).toLowerCase();
    } else{
        uri="";
    }

    System.out.println("method: ["+method + "] uri: [" + uri +"]");
    String msg = "";
    Map<String, String> parms = session.getParms();
    if ("".equals(uri)){
        //TextFiles.loadString just loads the whole file in a single string.
        msg=TextFiles.loadString("C:/server/index.html");
        return new NanoHTTPD.Response(msg);
    }else//handle log refreshing
    if ("log".equals(uri)){
        System.out.println("Log requested ...");
        while(!Logging.webLogQueue.isEmpty()){
            msg+="<p>"+Logging.webLogQueue.poll()+"</p>";
        }
        return new NanoHTTPD.Response(msg);
    }else if ("suites".equals(uri)){
        System.out.println("suites requested ...");

        // fill msg with suites  ...

        return new NanoHTTPD.Response(msg);
    } else if (("status".equals(uri))){
        System.out.println("status requested ...");
        msg=(isTesting?"Testing...":"Idle");
        return new NanoHTTPD.Response(msg);
    }else{
        for(String paramKey:parms.keySet()){
            String[] value=params.get(paramKey).split(" ");
            Logging.log("<p>"+Logging.getTimeStamp()+" Parameter: "+paramKey+"="+    params.get(paramKey)+"</p>");
            if ("tcl".equalsIgnoreCase(paramKey)){
                Logging.log("run started : "+params.get(paramKey));
                while(isTesting){
                    try {
                        Logging.log("test pending : "+params.get(paramKey));
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Logging.log("test starting: "+params.get(paramKey));
                //Raise a flag while executing a test run
                isTesting=true;
                try {
                    Logging.log("Attempting to execute: "+params.get(paramKey));
                    BananaTest.execute(value);
                    Logging.log("Ttest finished: "+params.get(paramKey));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                isTesting=false;
            }
        }
    }
    msg=TextFiles.loadString("C:/server/index.html");
    return new NanoHTTPD.Response(msg);
}


public static void main(String[] args) {
    ServerRunner.run(TestServer.class);
}

}

index.html

<html>
<style>
h1 {
    color: green;
    background-color: black;
}
p {
    color: gray;
    background-color: black;
}
div {
    color: gray;
    background-color: black;
}
body {
    color: gray;
    background-color: black;
}
</style>

<head>
<script src="file///jquery-1.8.2.min.js"></script>

<script>
    // tail effect
    function tailScroll() {
        if (document.getElementById("auto-scroll").checked) {
            var height = $("#log-container").get(0).scrollHeight;
            $("#log-container").animate({
                scrollTop: height
            }, 500);
        }


    }

    var auto_refresh_log = setInterval(
        function() {
            var statusDiv = document.getElementById("status");
            if (statusDiv.innerHTML.indexOf("Idle.") < 0) {
                $.get("log",
                    function(data, status) {
                        if (data) {
                            var logDiv = document.getElementById("log");
                            $("#log").append(data);
                            tailScroll();
                        };
                        }
                )
            }


        }, 500
    );


    var auto_refresh_status = setInterval(
        function() {
            $('#status').load("status").fadeIn("slow");
        }, 500);



    $(document).ready(function() {
        $('#suites').load("suites").fadeIn("slow");
        $('#status').load("status").fadeIn("slow");
        $('#war-info').load("war-info").fadeIn("slow");
        $('#log').load("log").fadeIn("slow");
        $('#build').load("build").fadeIn("slow");
        $("#results").hide();
        document.getElementById("auto-scroll").checked = true;
    });

    function getSuites() {
        $('#suites').load("suites").fadeIn("slow");
    }

    function runSuites() {
        //clearLog();
        var collection = document.getElementById("suites").getElementsByTagName('INPUT');
        var suiteList = "";
        for (var x = 0; x < collection.length; x++) {
            if (collection[x].type.toUpperCase() == 'CHECKBOX')
                if (collection[x].checked) {
                    suiteList = suiteList + " " + collection[x].id;
                }
        }
        //if no suite selected don't send 
        if (suiteList) {
            $.get("/get?tcl=" + suiteList.substring(1));
        }
    }

    function execute() {
        var text = $('textarea#gtester').val();
        //if no suite selected don't send 
        if (text) {
            $.get("/get?tcl=" + text);
            $('textarea#gtester').val('');
        }
    }

    function clearLog() {
        var logDiv = document.getElementById("log");
        logDiv.innerHTML = "";
    }

    function restartServer() {
        $.get("restart");
        window.location.reload(1);
    }

    function restartSolr() {
        $.get("restart-solr");
    }

    function restartSonar() {
        $.get("restart-sonar");
    }

    function pause() {
        $.get("pause");
    }

    function abort() {
        $.get("abort");
    }

    $("form#data").submit(function() {

        var formData = new FormData($(this)[0]);



        $.ajax({
            url: window.location.pathname,
            type: 'POST',
            data: formData,
            async: false,
            success: function(data) {
                alert(data)
            },
            cache: false,
            contentType: false,
            processData: false
        });

        return false;
    });

    function selectAll(cb){
        var collection = document.getElementById("suites").getElementsByTagName('INPUT');
        for (var x=0; x<collection.length; x++) {
                if (collection[x].type.toUpperCase()=='CHECKBOX')
                collection[x].checked = cb.checked;
        }
    }

    function toggleLog(){
        if ($('#log').is(':visible')) {   
             $('#log').hide();
             $('#results').show();
        }else{
            $('#log').show();    
            $('#results').hide();
        }
    }
</script>



</head>

<body >
<dev id="build" style="float:right;">   </dev>
<h1>Remote Test Service</h1>




<dev>

    <dev>
        <!--<button id="get-suites" onclick="getSuites()">Get latest suite list</button> -->
        <button id="run-suites" onclick="runSuites()" style="background: lightgreen; ">Run Tests</button>
        <button id="pause" onclick="pause()">Pause Test</button>
        <button id="abort" onclick="abort()">Abort Test</button> 
    </dev>



    <dev style="float=right">
        <button id="restart-test" onclick="restartServer()">Restart Test Server</button>
        <button id="restart-solr" onclick="restartSolr()">Restart Solr Server</button>
        <button id="restart-sonar" onclick="restartSonar()" >Restart Sonar Service</button>
    </dev>


     <h3>
     <b>Status:</b> 
     <dev id="status" > 

     </dev> 
     </h3>





</dev>




<dev id="main" >


    <dev style="width: 30%; float:left; height: 80%;  overflow: auto;">


        <dev>
            <hr>
          <h2>Banana Tests: </h2> 
          <input type="checkbox" id="selectAll" onclick='selectAll(this);'>Select All <br>     </input>    
        </dev>

        <hr>
        <dev id="suites" style="overflow-y: auto; white-space: nowrap;">

        </dev>


        <hr>

        <h3>WAR file Upload: </h3>
        <form id="datafiles" method="post" enctype="multipart/form-data">
            <input name="warfile" type="file" />
            <!-- <input type="text" name="Description" value="WAR file description..."  /> !-->
            <button>Submit</button>
        </form>
        <dev>
            <h3> <a href="file///D:/solr-4.8.1/searchlogs/webapps/banana.war" download>Download current War file</a></h3>
            <hr>
            <dev>
                <h3>Current WAR file info: </h3> </dev>
            <dev id="war-info"> </dev>
        </dev>
        <hr>
        <dev>
            <h3>
        <b>GTester Console:</b> <button id="execute" onclick="execute()">Execute</button>
        </h3>

            <textarea id="gtester" cols="50" rows="1" onkeydown="if (event.keyCode == 13) { execute(); return false; }">

            </textarea>


        </dev>
    </dev>

    <dev id="log-super-container" style="width: 70%; float:right; height: 80%;  overflow-y:auto; overflow-x:auto; white-space: nowrap;">
        <dev style="float:left;">
           <button id="clear-log" onclick="clearLog()" >Clear log</button>  
           <button id="toggle-log" onclick="toggleLog()" >Log/TCs state</button>
           <input type="checkbox" id="auto-scroll" >Auto scroll <br> </input>          
        </dev>
        <dev style="float:left;">

        </dev>



        <dev id="log-container" style="width: 100%; height: 95%; float:right; overflow:auto; ">
            <dev id="log" style="overflow: auto; white-space: nowrap;">

            </dev>
            <dev id="results" style="overflow: auto; white-space: nowrap;">
                <h3>Passed:<br></h3>
                <dev id="passed"> 
                    0
                </dev>
                <h3>Current:<br></h3>    
                <dev id="current"> 
                    0
                </dev>
                <h3>Failed:<br></h3>
                <dev id="failed"> 
                    0
                </dev>

            </dev>

        </dev>


    </dev>




</dev>


</body>

</html>
Amr Lotfy
  • 2,937
  • 5
  • 36
  • 56