Skip to content

The Request Class

NoteFox edited this page Jul 10, 2020 · 1 revision

The Request itself is its own Object where the "magic is happening" (creating and converting osm and map Files to the users liking).

For that, it uses the following environmental Tools :

These need to be installed! (If they are not, incoming requests will always end up throwing an Error. So please make sure to follow the Set Up first)


Variables

Name Type Standard Value Description Authors Note
coordinates List null (defined in Constructor) Coordiantes used for the map boundaries
date String null (defined in Constructor) requested map date
mapName String null (defined in Constructor) individual mapName
requestedByID String null (defined in Constructor) id that requested this request
startTime LocalDateTime LocalDateTime.now() Time the Request was Created
runtimeStart LocalDateTime null Time the Request was started
endTime LocalDateTime null Time the Request was stopped or ran out
status QueryRequestStatus QueryRequestStatus.REQUESTED status of the Request
errorMessage String "" error mEssage of the Request (if empty then there is no error message to be found)
TAG String null (defined in Constructor) TAG for the Logger
LOG String "" LOG temporary String holder for the ".req"
osmDir String null (defined in Constructor) Path, where the ".osm" File will be saved
mapDir String null (defined in Constructor) Path where the ".map" File will be saved
sLogDir String null (defined in Constructor) ".req" save File Path
renderingParameter String null (defined in Constructor) renderingParameter File for the rendering of the osm file
ohdmConverter String null (defined in Constructor) ohdmConverter path for the download of the osm map
javaJdkPath String null (defined in Constructor) javaJdkPath for the execution of enviromental Tools that use java
jdbcDriverPath String null (defined in Constructor) jdbcDriver for the OHDMConverter
individualLogFile String null (defined in Constructor) individualLogFile name
stopThread boolean false shows if the thread is stopped

QueryRequestStatus

This object itself has 5 different kinds of States it can be in:

  1. REQUESTED
    • just got Requested from the App or the Browser
    • not yet started
    • already created the individualLogFile (".req" File) for the Request
  2. DOWNLOADING
    • just started (has a runtimeStart)
    • just updated the individualLogFile
    • just started, can be stopped
    • currently using the OHDMConverter / OSMImportTool to download the osm File
  3. CONVERTING
    • currently converting the downloaded .osm File to a usable .map File for the App to use
    • .osm can already be downloaded from the website
  4. DONE
    • The Request is done (has an endTime now)
    • .osm and .map file were successfully created and now downloadable
    • the Error String is empty
    • the individual logFile will not be touched from now on
    • the Thread has stopped
  5. ERROR
    • The Request encountered an fatal Error during the download or conversion process (has an endTime now)
    • the .map File will not be available ( the .osm file could be available if the Error occured in the Convertion process)
    • the Error String is filled with the occured error full stacktrace
    • the individual logFile will not be touched from now on
    • the Thread has stopped

Constructor

public QueryRequest(List<Coords> coordinates, String date, String mapName, String id, String osmDir, String mapDir, String sLogDir, String renderingParameter, String ohdmConverter, String javaJdkPath, String jdbcDriverPath) {
    this.osmDir = osmDir;
    this.mapDir = mapDir;
    this.sLogDir = sLogDir;

    this.renderingParameter = renderingParameter;
    this.ohdmConverter = ohdmConverter;

    this.javaJdkPath = javaJdkPath;
    this.jdbcDriverPath = jdbcDriverPath;

    this.coordinates = coordinates;
    this.date = date;
    this.mapName = mapName;
    this.requestedByID = id;

    this.individualLogFile = sLogDir + "/" + mapName + ".req";

    TAG = mapName + "_" + getRequestedByID() + "-Thread";
}

The Enviromental Tool Execution (ETE)

The Enviromental Code Execution is one of the parts that shows the basis of what is maybe to come in this current project. It shows how to properly use outside tools to execute and influence the current Thread. For the execution of "Outside Tools" and the processing of the retun values, the Method "execCommadn" war written.

​ The main thing it does is this :

Process p = null;
p = Runtime.getRuntime.exec(command);
p.waitFor();

So it gets the enviromental runtime and executes a specific command wich gives back a process that is running. After that, the curren Thread is forced to wait, till this Process is done.

Authors Note: This excCommand() Method can be reused everywhere! You can get the input-streams of the process to get the outputs of it. You can also do many other things with the "Process Object". Try it four yourself, it's fun.


The "download_map" and "convert_map" Methods

These two Methods are used, to run specific Commands with the before mentioned Enviromental Tool Execution (ETE) Method.

​ Basically the follwing 2 steps are taken to execute the two tools ( OHDMConverter / osmosis ) :

  1. A template is created with the needed inputs for the ETE

    • download_map

      String[] template = new String[]{javaJdkPath, "-classpath", jdbcDriverPath, "-jar", ohdmConverter, "-o",
              osmDir + "/" + mapName + ".osm", "-r", renderingParameter, "-p",
              rearrangeCoordsForScript(getCoordinates()), "-t", date};
    • convert_map

      String[] template = new String[]{"/opt/osmosis/bin/osmosis", "--rx", "file=" + osmDir + "/" + mapName + ".osm", "--mw", "file=" + mapDir + "/" + mapName + ".map"};
  2. the tempalte is then given to ETE and the results are then taken and put into the result Object (CommandReturn)

    result = excCommand(template);
    assert result != null;
    Logger.instance.addLogEntry(LogType.INFO, TAG,"output: " + result.output);
    Logger.instance.addLogEntry(LogType.ERROR, TAG,"error: " + result.errOutput);
    Logger.instance.addLogEntry(LogType.INFO, TAG,"return code: " + result.returnCode);
    
    LOG += "map : \noutput : " + result.output + "\n";
    LOG += "error : " + result.errOutput + "\n";
    LOG += "return code : "+result.returnCode + "\n\n";
    return result;

The "run" Method

@Override
    public void run() {
        // setting the start time
        runtimeStart = LocalDateTime.now();
        try {
            //Logger.instance.addLogEntry(LogType.INFO, TAG,"started request : " + date + " | " + getPrintableCoordsString());
            // setting the status to "DOWNLOADING"
            status = QueryRequestStatus.DOWNLOADING;
            refreshIndivLogFile();

            // declaring the Command returner ( here because of the scope of usage )
            CommandReturn returnMessage = new CommandReturn(0, "", "", null);

            try {
                // calling the download_method app to start the map_download
                // the return message is constructed in the download Method and is used here
                returnMessage = download_map();

                // In case the Method download_map was interrupted, because the Method "stopThread" was called.
                // Then here the status will be set to error + the errorMessage will be set appropriately
                // and the individual log file will be refreshed.
                // After that, this Thread will be terminated
                if (stopThread) {
                    status = QueryRequestStatus.ERROR;
                    endTime = LocalDateTime.now();
                    errorMessage = "Thread stopped manually";
                    refreshIndivLogFile();
                    return;
                }

                // Since some Tools use the error Output for Debugging purposes,
                // the error will only be caught, if an Exception was thrown into the ErrorOutput.
                // If the Exception is caught, the error message will be set accordingly to the errorOutput of the Process
                // and the individual log file will be refreshed.
                // After that, this Thread will be terminated
                if (returnMessage.errOutput.contains("Exception")) {
                    errorMessage = returnMessage.errOutput;
                    status = QueryRequestStatus.ERROR;
                    endTime = LocalDateTime.now();
                    refreshIndivLogFile();
                    return;
                }

                // if any other exceptions where thrown, then these will be put into
                // the error message and the the Thread will be terminated
            } catch (Exception e) {
                errorMessage = "Error in DOWNLOADING: " + returnMessage.errOutput;
                endTime = LocalDateTime.now();
                refreshIndivLogFile();
                return;
            } finally {
                // whatever will happen, an update to the ".req" file will always happen
                refreshIndivLogFile();
            }

            // after the download of the osm File was complete,
            // this will be Logged and the status will be set to the next step
            Logger.instance.addLogEntry(LogType.INFO, TAG,"download done - now converting");
            status = QueryRequestStatus.CONVERTING;

            try {
                // calling the convert_map app to start the map conversion ( with osmosis )
                // the return message is constructed in the download Method and is used here
                returnMessage = convert_map();

                // In case the Method download_map was interrupted, because the Method "stopThread" was called.
                // Then here the status will be set to error + the errorMessage will be set appropriately
                // and the individual log file will be refreshed.
                // After that, this Thread will be terminated
                if (stopThread) {
                    status = QueryRequestStatus.ERROR;
                    errorMessage = "Thread stopped manually";
                    endTime = LocalDateTime.now();
                    refreshIndivLogFile();
                    return;
                }
                // if any other exceptions where thrown, then these will be put into
                // the error message and the the Thread will be terminated
            } catch (Exception e) {
                status = QueryRequestStatus.ERROR;
                errorMessage = "Error in CONVERTING: " + returnMessage.errOutput + e.getStackTrace()[0];
                endTime = LocalDateTime.now();
                refreshIndivLogFile();
                return;
            } finally {
                // whatever will happen, an update to the ".req" file will always happen
                refreshIndivLogFile();
            }

            // If the last environmental Tool execution gave back some kind of error,
            // this will be handled here
            if (returnMessage.returnCode != 0) {
                // the status will be set accordingly
                status = QueryRequestStatus.ERROR;

                // here the last return code will be processed
                // the return code process is cookie-cut for this specific tool (osmosis)
                // I hope that the return codes won't change
                if (returnMessage.returnCode == -1) {
                    errorMessage = "ERROR in CONVERTING: File already exists. not overwriting it\n";
                    Logger.instance.addLogEntry(LogType.ERROR, TAG, errorMessage);
                    endTime = LocalDateTime.now();
                    refreshIndivLogFile();
                    return;
                }

                else if (returnMessage.returnCode == 2) {
                    errorMessage = "ERROR in CONVERTING: couldn't find File to convert";
                    Logger.instance.addLogEntry(LogType.ERROR, TAG, errorMessage);
                    endTime = LocalDateTime.now();
                    refreshIndivLogFile();
                    return;

                    // if the error code wasn't something normal or known
                    // the error will be logged here and put into the errorMessage as well
                } else {
                    Logger.instance.addLogEntry(LogType.ERROR, TAG, "Error:" + returnMessage.errOutput + "\nOutput:" + returnMessage.output);
                    errorMessage = returnMessage.errOutput;
                    endTime = LocalDateTime.now();
                    refreshIndivLogFile();
                    return;
                }

            }

            // if everything has gone good so far, 
            // the status will be set to DONE and the Thread will run out.
            // of course the ".req" File will be updated 
            status = QueryRequestStatus.DONE;
            endTime = LocalDateTime.now();
            refreshIndivLogFile();
        } catch (Exception e) {
            // if any other exceptions where thrown, then these will be put into
            // the error message and the the Thread will be terminated
            status = QueryRequestStatus.ERROR;
            Logger.instance.addLogEntry(LogType.ERROR, TAG, "Error:" + e.getStackTrace()[0]);
            errorMessage = "ERROR | " + e.getStackTrace()[0];
            endTime = LocalDateTime.now();
        } finally {
            try {
                // whatever will happen, an update to the ".req" file will always happen
                refreshIndivLogFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

Custom Classes

Coords

The Coords Class is used to save Coordinates. If there will ever be a change in how the Cooridantes will be saved, it can be schanged here.

public class Coords {
    public Double x;
    public Double y;

    public Coords(double x, double y) {
        this.x = Double.valueOf(new DecimalFormat("##.#####").format(x).replaceAll(",", "."));
        this.y = Double.valueOf(new DecimalFormat("##.#####").format(y).replaceAll(",", "."));
    }

    @Override
    public String toString() {
        return String.valueOf(x.toString() + ' ' + y.toString());
    }
}

CommandReturn

The CommandReturn Object is used in the execution of enviromental Tools (listed in the beginning of this Doc File). It combines:

  • The process used,
  • the standard Output,
  • the Error Output and ...
  • the execution return Code.
public class CommandReturn {
    public int returnCode;
    public String output;
    public String errOutput;

    private Process originalProcess;

    public CommandReturn(int returnCode, String output, String errOutput, Process originalProcess) {
        this.returnCode = returnCode;
        this.output = output;
        this.errOutput = errOutput;
        this.originalProcess = originalProcess;
    }

    public Process getOriginalProcess() {
        return originalProcess;
    }
}