Commit 0f1c41b0 authored by duminil's avatar duminil
Browse files

novaFactory : Saving file to TmpFolder

parent 6eac4c9f
......@@ -4,26 +4,27 @@
import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import eu.simstadt.nf4j.Connector;
import eu.simstadt.nf4j.ExportJob;
import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.InvalidJobDescriptorException;
import eu.simstadt.nf4j.JobStatus;
import eu.simstadt.nf4j.Connector;
/**
* Export jobs are requests for CityGML models. Every valid export job has an id and a status. This implementation
* offers non-blocking asynchronous send, poll and download operations, so that your main application has not to
* wait for the results. You may want to register your main application as a job status listeners at this job to
* get status updates from the asynchronous operations.
* offers non-blocking asynchronous send, poll and download operations, so that your main application has not to wait
* for the results. You may want to register your main application as a job status listeners at this job to get status
* updates from the asynchronous operations.
*
* @author Marcel Bruse
*/
public class AsyncExportJob extends ExportJob<ExportJobDescription> implements AsyncJob {
public class AsyncExportJob extends ExportJob<ExportJobDescription> implements AsyncJob
{
/**
* While polling for the current job status, the polling thread will sleep for this amount of seconds
* before each status update request.
* While polling for the current job status, the polling thread will sleep for this amount of seconds before each
* status update request.
*/
private final int DEFAULT_POLLING_INTERVAL = 5; // seconds
......@@ -37,8 +38,8 @@ public class AsyncExportJob extends ExportJob<ExportJobDescription> implements A
private Thread downloadThread;
/**
* Once the send() operation has been triggered, this member will be true. No subsequent invocations of
* send() will be possible then.
* Once the send() operation has been triggered, this member will be true. No subsequent invocations of send() will
* be possible then.
*/
private boolean jobTransmissionTriggered = false;
......@@ -46,14 +47,14 @@ public class AsyncExportJob extends ExportJob<ExportJobDescription> implements A
private boolean keepPolling = true;
/**
* List of all registered job status listeners. Whenever the state of this job changes, these listeners
* will get informed.
* List of all registered job status listeners. Whenever the state of this job changes, these listeners will get
* informed.
*/
private LinkedList<JobStatusListener> jobListenerList = new LinkedList<>();
/**
* This job will be send and observed asynchronously. It's results will be downloaded asynchronously also.
* If an asynchronous operation breaks, then the last encountered problem will be described here.
* This job will be send and observed asynchronously. Its results will be downloaded asynchronously also. If an
* asynchronous operation breaks, then the last encountered problem will be described here.
*/
private Optional<String> lastEncounteredProblem = Optional.empty();
......@@ -66,9 +67,9 @@ public class AsyncExportJob extends ExportJob<ExportJobDescription> implements A
private File result;
/**
* This constructor forces the job to have a description and a connector instance. Every job which
* is created by this constructor will have the status "local", because it is assumed that it has an unsent
* description and no job id yet.
* This constructor forces the job to have a description and a connector instance. Every job which is created by this
* constructor will have the status "local", because it is assumed that it has an unsent description and no job id
* yet.
*
* @param connector The job will use this connector to synchronize itself with the nF.
* @param descriptor The description of this job.
......@@ -80,11 +81,11 @@ public AsyncExportJob(ExportJobDescription descriptor, Connector<AsyncImportJob,
/**
* This constructor forces the job to have a id and a connector instance. Every job which is created by this
* constructor will have the status "sent", because it is assumed that the job is already enqueued at the
* nF job queue.
* constructor will have the status "sent", because it is assumed that the job is already enqueued at the nF job
* queue.
*
* @param id The job id. If you call updateStatus() and the nF "knows" the job id, then the job status
* will be updated. If you call updateStatus() and the job id is "unkown" on the server side, then
* @param id The job id. If you call updateStatus() and the nF "knows" the job id, then the job status will be
* updated. If you call updateStatus() and the job id is "unkown" on the server side, then
* @param connector The job will use this connector to synchronize itself with the nF.
*/
public AsyncExportJob(int id, Connector<AsyncImportJob, AsyncExportJob> connector) {
......@@ -93,8 +94,8 @@ public AsyncExportJob(int id, Connector<AsyncImportJob, AsyncExportJob> connecto
}
/**
* Builds an XML job file from the job description and sends it to the nF server which has been configured
* in your connector instance. This will be done asynchronously within a SendExportJobTask.
* Builds an XML job file from the job description and sends it to the nF server which has been configured in your
* connector instance. This will be done asynchronously within a SendExportJobTask.
*
* @throws FailedTransmissionException If this method has been called before, then you will receive this.
* @throws InvalidJobDescriptorException If the job description is invalid or null, then you will receive this.
......@@ -114,15 +115,14 @@ public synchronized void send() throws FailedTransmissionException, InvalidJobDe
}
/**
* Frequently queries the status of the remote nF export job and updates the local status accordingly.
* The queries will be performed asynchronously in a separate thread. Job status listeners will be notified
* upon every new status change.
* Frequently queries the status of the remote nF export job and updates the local status accordingly. The queries
* will be performed asynchronously in a separate thread. Job status listeners will be notified upon every new status
* change.
*
* Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously
* started poll threads.
* Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously started
* poll threads.
*
* @param interval Amount of seconds to wait before the next status update request will be sent to the
* nF server.
* @param interval Amount of seconds to wait before the next status update request will be sent to the nF server.
*
* @throws FailedTransmissionException If your job has not been sent yet, then you will get some of this.
*/
......@@ -142,15 +142,14 @@ public synchronized void poll(int interval) throws FailedTransmissionException {
/**
* Convenience method for polling with a predefined default interval.
*
* Frequently queries the status of the remote nF export job and updates the local status accordingly.
* The queries will be performed asynchronously in a separate thread. Job status listeners will be notified
* upon every new status change.
* Frequently queries the status of the remote nF export job and updates the local status accordingly. The queries
* will be performed asynchronously in a separate thread. Job status listeners will be notified upon every new status
* change.
*
* Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously
* started poll threads.
* Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously started
* poll threads.
*
* @param interval Amount of seconds to wait before the next status update request will be sent to the
* nF server.
* @param interval Amount of seconds to wait before the next status update request will be sent to the nF server.
* @throws FailedTransmissionException If your job has not been sent yet, then you will get some of this.
* @see poll(int)
*/
......@@ -159,12 +158,12 @@ public synchronized void poll() throws FailedTransmissionException {
}
/**
* Connects to the nF and refreshes the status of this job. If there is no nF connector set,
* this operation will throw a FailedTransmissionException.
* Connects to the nF and refreshes the status of this job. If there is no nF connector set, this operation will
* throw a FailedTransmissionException.
*
* @throws FailedTransmissionException You will receive this exception if no connector is present, the connection
* to the nF is broken, the job has not been sent to the nF yet, or another update request is ongoing. In the two
* latter cases, job will either have the status "LOCAL" or "WAITING".
* @throws FailedTransmissionException You will receive this exception if no connector is present, the connection to
* the nF is broken, the job has not been sent to the nF yet, or another update request is ongoing. In the
* two latter cases, job will either have the status "LOCAL" or "WAITING".
*/
@Override
public synchronized void updateStatus() throws FailedTransmissionException {
......@@ -182,8 +181,8 @@ public synchronized void updateStatus() throws FailedTransmissionException {
}
/**
* Calls updateStatus() for you, since updateStatus() is a protected method. This method is used by the
* asynchronous PollJobStatusTask class.
* Calls updateStatus() for you, since updateStatus() is a protected method. This method is used by the asynchronous
* PollJobStatusTask class.
*/
@Override
public void triggerStatusUpdate() throws FailedTransmissionException {
......@@ -191,8 +190,8 @@ public void triggerStatusUpdate() throws FailedTransmissionException {
}
/**
* Sets the status of this job depending on the given nF status code. nF status codes will be sent
* to you in http responses.
* Sets the status of this job depending on the given nF status code. nF status codes will be sent to you in http
* responses.
*
* @param statusCode The nF status code for this job.
*/
......@@ -200,21 +199,25 @@ public void triggerStatusUpdate() throws FailedTransmissionException {
public synchronized void setStatusForCode(int statusCode) {
switch (statusCode) {
case 0:
setStatus(JobStatus.PENDING); break;
setStatus(JobStatus.PENDING);
break;
case 10:
setStatus(JobStatus.RUNNING); break;
setStatus(JobStatus.RUNNING);
break;
case 20:
setStatus(JobStatus.FAILED); break;
setStatus(JobStatus.FAILED);
break;
case 30:
setStatus(JobStatus.FINISHED); break;
setStatus(JobStatus.FINISHED);
break;
default:
setStatus(JobStatus.UNKNOWN);
}
}
/**
* @return Returns true, if the job is definitely done. This is also the case, if the resulting CityGML
* file has been download. False, otherwise.
* @return Returns true, if the job is definitely done. This is also the case, if the resulting CityGML file has been
* download. False, otherwise.
*/
@Override
public boolean hasFinished() {
......@@ -222,8 +225,7 @@ public boolean hasFinished() {
}
/**
* @return Returns true, if the job has been failed. You may want to look up the "last encountered problem"
* string.
* @return Returns true, if the job has been failed. You may want to look up the "last encountered problem" string.
*/
@Override
public boolean hasFailed() {
......@@ -234,8 +236,8 @@ public boolean hasFailed() {
* Registers a job status listener.
*
* @param jobListener The job status listener to be registered. This listener will receive updates about every
* progressing change of the job status. Meaning, the change to a particular status will only be signaled once
* to the listener.
* progressing change of the job status. Meaning, the change to a particular status will only be signaled
* once to the listener.
*/
@Override
public void addJobStatusListener(JobStatusListener jobListener) {
......@@ -253,10 +255,9 @@ public void removeJobStatusListener(JobStatusListener jobListener) {
}
/**
* Once the status of this job changes, all registered job status listeners will be notified.
* Listeners will only be notified of the status updates where the status of the job progresses and they will
* only be notified once about every singular status. If this status has been signaled already, then the
* listeners will not be notified again.
* Once the status of this job changes, all registered job status listeners will be notified. Listeners will only be
* notified of the status updates where the status of the job progresses and they will only be notified once about
* every singular status. If this status has been signaled already, then the listeners will not be notified again.
*/
@Override
public synchronized void notifyJobStatusListeners() {
......@@ -295,12 +296,11 @@ public boolean keepPolling() {
}
/**
* Starts downloading the export job result, if there is any. As soon as the download has been finished,
* the job status will be set to DOWNLOADED. All registered job status listeners will get notified about
* the it. Afterwards, you may want to obtain a handle to the download CityGML file with getResult().
* Starts downloading the export job result, if there is any. As soon as the download has been finished, the job
* status will be set to DOWNLOADED. All registered job status listeners will get notified about the it. Afterwards,
* you may want to obtain a handle to the download CityGML file with getResult().
*
* @throws FailedTransmissionException If the job has not been finished yet, then you will get some
* of this.
* @throws FailedTransmissionException If the job has not been finished yet, then you will get some of this.
*/
public void downloadResult() throws FailedTransmissionException {
if (!hasFinished()) {
......@@ -311,8 +311,7 @@ public void downloadResult() throws FailedTransmissionException {
}
/**
* This method is used by the download task to set the CityGML file handle as soon as the file has
* been download.
* This method is used by the download task to set the CityGML file handle as soon as the file has been download.
*
* @param result The file handle of the download CityGML file.
*/
......@@ -321,13 +320,12 @@ protected void setResult(File result) {
}
/**
* This method will return the download CityGML file for this export job, but only if the export job has
* actually been finished before.
* This method will return the download CityGML file for this export job, but only if the export job has actually
* been finished before.
*
* @return Returns a file handle to the download CityGML file.
*
* @throws FailedTransmissionException If the job result has not been download yet, then you will get some
* of this.
* @throws FailedTransmissionException If the job result has not been download yet, then you will get some of this.
*/
@Override
public File getResult() throws FailedTransmissionException {
......@@ -343,8 +341,8 @@ public File getResult() throws FailedTransmissionException {
/**
* The asynchronous send, poll and download tasks cannot throw exceptions. If something goes wrong during the save,
* poll or download operation, then you may want to submit at lease a textual description of the problem here. This
* message will be sent to all registered job status listeners on the next status update. This is why you can use
* the convenience method setStatus(jobStatus, message), to do both at the same time.
* message will be sent to all registered job status listeners on the next status update. This is why you can use the
* convenience method setStatus(jobStatus, message), to do both at the same time.
*
* @param errorMessage The description of the encountered problem. This could be the exception message or a more user
* friendly message.
......
......@@ -19,23 +19,21 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import eu.simstadt.nf4j.Job;
import eu.simstadt.nf4j.Connector;
import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.InvalidJobDescriptorException;
import eu.simstadt.nf4j.Job;
import eu.simstadt.nf4j.JobStatus;
import eu.simstadt.nf4j.Connector;
/**
* NFConnector lets you communicate with your novaFACTORY (nF) server instance. It supports nF version 6.3.1.1.
* For more technical details about the NFConnector interface @see NFConnector.
* NFConnector lets you communicate with your novaFACTORY (nF) server instance. It supports nF version 6.3.1.1. For more
* technical details about the NFConnector interface @see NFConnector.
*
* Please note, that this connector doesn't act asynchronously. This connector is safe, but will block your main
* application. You may rather want to use the asynchronous job implementations.
......@@ -45,7 +43,8 @@
* @param <I> The import job descriptor implementation for this connector.
* @param <E> The export job descriptor implementation for this connector.
*/
public class HTTPConnection implements Connector<AsyncImportJob, AsyncExportJob> {
public class HTTPConnection implements Connector<AsyncImportJob, AsyncExportJob>
{
/** Supported version of the novaFACTORY. */
public static final String NOVA_FACTORY_VERSION = "6.3.1.1";
......@@ -126,9 +125,9 @@ public HTTPConnection(String server, int port, String context, String protocol)
* Callers of this NFConnector want to know the actual version of the novaFACTORY and the versions of its
* HTTP/FTP/WPS/etc. interfaces against which this interface has been implemented.
*
* The NovaFACTORY interfaces may change over time. Such changes force the SimStadt programmers to
* implement different versions of this NFConnector interface while keeping old implementations in order to
* ensure backward compatibility.
* The NovaFACTORY interfaces may change over time. Such changes force the SimStadt programmers to implement
* different versions of this NFConnector interface while keeping old implementations in order to ensure backward
* compatibility.
*
* @return The supported version of the novaFACTORY.
*/
......@@ -229,8 +228,7 @@ private String buildParameter(String key, Object value) {
}
/**
* Builds a HTTP GET request URL out of the used protocol, nF server, port, context, servlet and existing
* parameters.
* Builds a HTTP GET request URL out of the used protocol, nF server, port, context, servlet and existing parameters.
*
* @param servlet One of the supported nF servlets RemoteOrder, RemoteStatus or RemoteImport.
* @param parameters List of parameters to be send to the servlet.
......@@ -248,11 +246,11 @@ private URL buildURL(String servlet, List<String> parameters) throws MalformedUR
/**
* Requests a response from the given URL. The response is expected to be returned as nF XML report.
*
* @param url The URL of the nF servlet with all its necessary parameters. Read the nF handbook for more
* details about the usage of nF servlets.
* @param url The URL of the nF servlet with all its necessary parameters. Read the nF handbook for more details
* about the usage of nF servlets.
* @return The response is expected to be a XML report, which will then be returned as a String.
* @throws IOException You will get some of this, if anything goes wrong with your data connection to your
* nF instance.
* @throws IOException You will get some of this, if anything goes wrong with your data connection to your nF
* instance.
*/
private String getResponse(URL url) throws UnsupportedEncodingException, IOException {
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
......@@ -263,12 +261,12 @@ private String getResponse(URL url) throws UnsupportedEncodingException, IOExcep
/**
* Requests a response from the given HTTP connection. The response is expected to be a XML document.
*
* @param httpConnection The HTTP Connection to the nF servlet. Read the nF handbook for more details
* about the usage of the nF servlets.
* @param httpConnection The HTTP Connection to the nF servlet. Read the nF handbook for more details about the usage
* of the nF servlets.
* @return The response is expected to be a XML report, which will then be returned as a String.
* @throws UnsupportedEncodingException You will get some of this, if your connection uses wrong encodings.
* @throws IOException You will get some of this, if anything goes wrong with your data connection to your
* nF instance.
* @throws IOException You will get some of this, if anything goes wrong with your data connection to your nF
* instance.
*/
private String getResponse(HttpURLConnection httpConnection) throws UnsupportedEncodingException, IOException {
String xml = "";
......@@ -297,14 +295,14 @@ private String getResponse(HttpURLConnection httpConnection) throws UnsupportedE
}
/**
* If everything works as expected, then nF's servlets will respond with XML reports to your requests. The job
* id and status will be extracted from the response string. The id of the passed job instance will be updated.
* The XML reports have a certain structure. Read the nF manual for more information about the XML reports and
* have a look at the DTD of the XML reports.
* If everything works as expected, then nF's servlets will respond with XML reports to your requests. The job id and
* status will be extracted from the response string. The id of the passed job instance will be updated. The XML
* reports have a certain structure. Read the nF manual for more information about the XML reports and have a look at
* the DTD of the XML reports.
*
* @param xml A XML string that is supposed to be a XML document.
* @param An empty job status object about to be filled with the actual result. It will be UNKOWN if there was
* no XML report in the response.
* @param An empty job status object about to be filled with the actual result. It will be UNKOWN if there was no XML
* report in the response.
* @throws ParserConfigurationException Something went wrong.
* @throws SAXException Some parse error.
* @throws IOException Some parse error.
......@@ -331,8 +329,8 @@ private void getJobFromResponse(Job job, String xml)
* Downloads a (zipped) CityGML file from the nF server. The file will be the result of an export job.
*
* @param url The URL of the remote order servlet that points at the CityGML file on the nF server.
* @return Returns a handle to the downloaded (zipped) CityGML file. Will be null if no file has been
* downloaded (due to errors).
* @return Returns a handle to the downloaded (zipped) CityGML file. Will be null if no file has been downloaded (due
* to errors).
* @throws IOException Something went wrong with your data connection. Check your server and the port.
*/
private File downloadFile(URL url) throws IOException {
......@@ -352,7 +350,8 @@ private File downloadFile(URL url) throws IOException {
}
}
InputStream inputStream = httpConnection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(filename);
handle = Files.createTempDirectory("nfDownload").resolve(filename).toFile();
FileOutputStream outputStream = new FileOutputStream(handle);
int bytesRead = -1;
byte[] buffer = new byte[4096];
while ((bytesRead = inputStream.read(buffer)) != -1) {
......@@ -360,7 +359,6 @@ private File downloadFile(URL url) throws IOException {
}
outputStream.close();
inputStream.close();
handle = new File(filename);
} else {
throw new IOException();
}
......@@ -412,27 +410,23 @@ public void sendAndUpdateExportJob(AsyncExportJob job)
}
/**
* Sends an import job to nF. The given import job file has to be a zip file and has to obey the internal
* structure defined in the nF manuals. Short description:
* Sends an import job to nF. The given import job file has to be a zip file and has to obey the internal structure
* defined in the nF manuals. Short description:
*
* Import jobs enable you to add, alter and delete CityGML top level objects (like buildings) in the nF.
* Every import job file has to contain a start file. Start files control the import process through their
* file names and their contents. The name of a start file has the following structure
* Import jobs enable you to add, alter and delete CityGML top level objects (like buildings) in the nF. Every import
* job file has to contain a start file. Start files control the import process through their file names and their
* contents. The name of a start file has the following structure
*
* <Product>_<Tile>.start
*
* The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML
* file and the ZIP archive has to be named after the following naming convention:
* The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML file
* and the ZIP archive has to be named after the following naming convention:
*
* <Product>_<Tile>_<Level>_<Operation>.gml
*
* Here operation can be ...
* - 'REP': Replaces whole existing buildings only,
* - 'REPUPD': Replaces whole existing buildings and adds new buildings,
* - 'UPD': Update, same as REP,
* - 'CHG': Change, same as REPUPD,
* - 'DEL': Deletes the geometry of a particular LOD,
* - 'DELALL': Deletes a whole building
* Here operation can be ... - 'REP': Replaces whole existing buildings only, - 'REPUPD': Replaces whole existing
* buildings and adds new buildings, - 'UPD': Update, same as REP, - 'CHG': Change, same as REPUPD, - 'DEL': Deletes
* the geometry of a particular LOD, - 'DELALL': Deletes a whole building
*
* @param file The nF import job as a prepared ZIP file. It has to contain the CityGML file and the start file.
* @return Returns the job status of your import job.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment