Commit 23dfbe94 authored by bruse's avatar bruse
Browse files

- Added the first two test cases for export and import job transmissions

- Fixed minor errors
parent a2b74ef7
...@@ -48,7 +48,7 @@ public void sendAndUpdateExportJob(E exportJob) ...@@ -48,7 +48,7 @@ public void sendAndUpdateExportJob(E exportJob)
* <Product>_<Tile>.start * <Product>_<Tile>.start
* *
* The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML * The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML
* file has to be named after the following naming convention: * file and the ZIP archive to be sent has to be named after the following naming convention:
* *
* <Product>_<Tile>_<Level>_<Operation>.gml * <Product>_<Tile>_<Level>_<Operation>.gml
* *
......
...@@ -17,7 +17,8 @@ public abstract class Job { ...@@ -17,7 +17,8 @@ public abstract class Job {
protected Connector<?, ?> connector; protected Connector<?, ?> connector;
/** /**
* Every job has it's status. Look up the different possible values in the JobStatus enumeration. * Every job has a status. This method returns it. Look up the different possible values in the JobStatus
* enumeration.
* *
* @return Returns the status of this job. * @return Returns the status of this job.
*/ */
......
...@@ -114,8 +114,8 @@ public synchronized void send() throws FailedTransmissionException, InvalidJobDe ...@@ -114,8 +114,8 @@ public synchronized void send() throws FailedTransmissionException, InvalidJobDe
} }
/** /**
* Frequently queries the remote status of the nF export job and updates the local status accordingly. * 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 listener will be notified * The queries will be performed asynchronously in a separate thread. Job status listeners will be notified
* upon every new status change. * upon every new status change.
* *
* Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously * Note, there can only be one polling thread at a time. Subsequent calls of poll() will stop the previously
...@@ -142,6 +142,16 @@ public synchronized void poll(int interval) throws FailedTransmissionException { ...@@ -142,6 +142,16 @@ public synchronized void poll(int interval) throws FailedTransmissionException {
/** /**
* Convenience method for polling with a predefined default interval. * 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.
*
* 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.
* @throws FailedTransmissionException If your job has not been sent yet, then you will get some of this.
* @see poll(int) * @see poll(int)
*/ */
public synchronized void poll() throws FailedTransmissionException { public synchronized void poll() throws FailedTransmissionException {
......
...@@ -90,7 +90,7 @@ public synchronized void send() throws InvalidJobDescriptorException, FailedTran ...@@ -90,7 +90,7 @@ public synchronized void send() throws InvalidJobDescriptorException, FailedTran
} }
/** /**
* Frequently queries the remote status of the nF export job and updates the local status accordingly. * 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 listener will be notified * The queries will be performed asynchronously in a separate thread. Job status listener will be notified
* upon every new status change. * upon every new status change.
* *
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
public interface AsyncJob { public interface AsyncJob {
/** /**
* Frequently queries the remote status of the nF export job and updates the local status accordingly. * 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 listener will be notified * The queries will be performed asynchronously in a separate thread. Job status listener will be notified
* upon every new status change. * upon every new status change.
* *
......
...@@ -100,7 +100,7 @@ public class HTTPConnection implements Connector<AsyncImportJob, AsyncExportJob> ...@@ -100,7 +100,7 @@ public class HTTPConnection implements Connector<AsyncImportJob, AsyncExportJob>
private String context; private String context;
/** /**
* Constructs your NFConnector instance. * Constructs your Connector instance.
* *
* @param server The host name of the nF server with which you want to establish a data connection. * @param server The host name of the nF server with which you want to establish a data connection.
*/ */
...@@ -109,7 +109,7 @@ public HTTPConnection(String server) { ...@@ -109,7 +109,7 @@ public HTTPConnection(String server) {
} }
/** /**
* Constructs your NFConnector instance. * Constructs your Connector instance.
* *
* @param server The host name of the nF server with which you want to establish a data connection. * @param server The host name of the nF server with which you want to establish a data connection.
* @param port The port of the nF web application. * @param port The port of the nF web application.
...@@ -298,8 +298,9 @@ private String getResponse(HttpURLConnection httpConnection) throws UnsupportedE ...@@ -298,8 +298,9 @@ 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 * If everything works as expected, then nF's servlets will respond with XML reports to your requests. The job
* status will be extracted from the response string. The XML reports have a certain structure. Read the nF * id and status will be extracted from the response string. The id of the passed job instance will be updated.
* manual for more information about the XML reports and have a look at the DTD of the XML reports. * 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 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 * @param An empty job status object about to be filled with the actual result. It will be UNKOWN if there was
...@@ -421,7 +422,7 @@ public void sendAndUpdateExportJob(AsyncExportJob job) ...@@ -421,7 +422,7 @@ public void sendAndUpdateExportJob(AsyncExportJob job)
* <Product>_<Tile>.start * <Product>_<Tile>.start
* *
* The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML * The start file should contain the level to which your manipulated CityGML should be imported. Your CityGML
* file has to be named after the following naming convention: * file and the ZIP archive has to be named after the following naming convention:
* *
* <Product>_<Tile>_<Level>_<Operation>.gml * <Product>_<Tile>_<Level>_<Operation>.gml
* *
...@@ -466,6 +467,11 @@ public void sendAndUpdateImportJob(AsyncImportJob job) ...@@ -466,6 +467,11 @@ public void sendAndUpdateImportJob(AsyncImportJob job)
os.flush(); os.flush();
writer.append(CRLF).flush(); writer.append(CRLF).flush();
getJobFromResponse(job, getResponse(connection)); getJobFromResponse(job, getResponse(connection));
if (job.getId() > 0) {
job.setStatus(JobStatus.SENT, Optional.empty());
} else {
throw new FailedTransmissionException("Job didn't receive an id from the nF server.");
}
} catch (MalformedURLException ex) { } catch (MalformedURLException ex) {
job.getStatus().setMessage(MALFORMED_URL); job.getStatus().setMessage(MALFORMED_URL);
throw new FailedTransmissionException(ex.getMessage()); throw new FailedTransmissionException(ex.getMessage());
......
...@@ -36,7 +36,6 @@ public void run() { ...@@ -36,7 +36,6 @@ public void run() {
try { try {
HTTPConnection connector = (HTTPConnection) job.getConnector(); HTTPConnection connector = (HTTPConnection) job.getConnector();
connector.sendAndUpdateExportJob(job); connector.sendAndUpdateExportJob(job);
job.setStatus(JobStatus.SENT, Optional.empty());
job.poll(); job.poll();
} catch (InvalidJobDescriptorException ex) { } catch (InvalidJobDescriptorException ex) {
signalError("Job cancel because of an invalid job description!"); signalError("Job cancel because of an invalid job description!");
...@@ -46,10 +45,10 @@ public void run() { ...@@ -46,10 +45,10 @@ public void run() {
} }
/** /**
* This method is superfluous I guess? Please refactor it. * This method is superfluous I guess? TODO: Please check and refactor it.
*/ */
private void signalError(String errorMessage) { private void signalError(String errorMessage) {
job.setStatus(JobStatus.UNKOWN, Optional.of(errorMessage)); job.setStatus(JobStatus.UNKOWN, Optional.of(errorMessage));
} }
} }
\ No newline at end of file
...@@ -36,7 +36,6 @@ public void run() { ...@@ -36,7 +36,6 @@ public void run() {
try { try {
HTTPConnection connector = (HTTPConnection) job.getConnector(); HTTPConnection connector = (HTTPConnection) job.getConnector();
connector.sendAndUpdateImportJob(job); connector.sendAndUpdateImportJob(job);
job.setStatus(JobStatus.SENT, Optional.empty());
job.poll(); job.poll();
} catch (InvalidJobDescriptorException ex) { } catch (InvalidJobDescriptorException ex) {
signalError("Job cancel because of an invalid job description!"); signalError("Job cancel because of an invalid job description!");
...@@ -45,8 +44,11 @@ public void run() { ...@@ -45,8 +44,11 @@ public void run() {
} }
} }
/**
* This method is superfluous I guess? TODO: Please check and refactor it.
*/
private void signalError(String errorMessage) { private void signalError(String errorMessage) {
job.setStatus(JobStatus.UNKOWN, Optional.of(errorMessage)); job.setStatus(JobStatus.UNKOWN, Optional.of(errorMessage));
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async.test;
import java.io.File; import java.io.File;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import eu.simstadt.nf4j.FailedTransmissionException; import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.InvalidJobDescriptorException; import eu.simstadt.nf4j.InvalidJobDescriptorException;
import eu.simstadt.nf4j.JobStatus; import eu.simstadt.nf4j.JobStatus;
import eu.simstadt.nf4j.async.AsyncExportJob;
import eu.simstadt.nf4j.async.ExportJobDescription;
import eu.simstadt.nf4j.async.HTTPConnection;
import eu.simstadt.nf4j.async.JobStatusEvent;
import eu.simstadt.nf4j.async.JobStatusListener;
import eu.simstadt.nf4j.async.Layer;
import eu.simstadt.nf4j.async.Unit;
/** /**
* This is a class for development and test purposes. It is not needed for production. You may want to delete it. * This class contains client oriented export job tests. It will send an export job and listens to
* * status updates. Every of the subsequent status' LOCAL, SENT, PENDING, RUNNING, FINISHED and DOWNLOAD
* have to be signaled to this test class.
*
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class Client implements JobStatusListener { public class SuccessfulExportJob implements JobStatusListener {
public AsyncExportJob job; public AsyncExportJob job;
public static void main(String[] args) { @Test
Client client = new Client(); public void processJob() throws InterruptedException {
client.processJob();
}
public void processJob() {
// Describe the export job
ExportJobDescription description= ExportJobDescription.getDefaultDescriptor(); ExportJobDescription description= ExportJobDescription.getDefaultDescriptor();
description.setInitiator("2758"); description.setInitiator("2758");
description.setAccount("Bruse"); description.setAccount("Bruse");
description.setProduct("WU3"); description.setProduct("WU3");
description.setJobnumber("Bruse_0815"); description.setJobnumber("Bruse_0815");
// Set at least one unit. You could also define a region polygon.
Unit unit = Unit.getDefaultUnit(); Unit unit = Unit.getDefaultUnit();
unit.setValue("821"); unit.setValue("821");
description.addUnit(unit); description.addUnit(unit);
// Set at least one layer
Layer layer = Layer.getDefaultLayer(); Layer layer = Layer.getDefaultLayer();
layer.setProduct("WU3"); layer.setProduct("WU3");
layer.setName("GML"); layer.setName("GML");
description.addLayer(layer); description.addLayer(layer);
// Create a new export job with the job description and a HTTP connection
job = new AsyncExportJob(description, new HTTPConnection("193.196.136.164")); job = new AsyncExportJob(description, new HTTPConnection("193.196.136.164"));
// Register a job status listener
job.addJobStatusListener(this); job.addJobStatusListener(this);
try { try {
// Send the export job to the nF server in a separate thread
job.send(); job.send();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
// There was a problem with your connection or the job has been sent twice
ex.printStackTrace(); ex.printStackTrace();
} catch (InvalidJobDescriptorException ex) { } catch (InvalidJobDescriptorException ex) {
// The export job description is invalid
ex.printStackTrace(); ex.printStackTrace();
} }
// Wait for timeout, failure or that all tests pass
long timeout = 1000 * 60 * 3l; // 3 minutes maximum
long interval = 10000l;
while (!job.hasFinished() && !job.hasFailed() && timeout > 0) {
Thread.sleep(interval);
timeout -= interval;
}
} }
// This client is a job status listener and will get notified upon job status changes
@Override @Override
public void jobStatusChanged(JobStatusEvent event) { public void jobStatusChanged(JobStatusEvent event) {
JobStatus status = (JobStatus) event.getSource(); JobStatus status = (JobStatus) event.getSource();
System.out.println(status); System.out.println(status);
if (status == JobStatus.FINISHED) { if (status == JobStatus.LOCAL) {
assertTrue(true);
} else if (status == JobStatus.SENT) {
assertTrue(true);
} else if (status == JobStatus.PENDING) {
assertTrue(true);
} else if (status == JobStatus.RUNNING) {
assertTrue(true);
} else if (status == JobStatus.FINISHED) {
try { try {
// Start an asynchronous download of the resulting CityGML file assertTrue(true);
job.downloadResult(); job.downloadResult();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
// Only finished jobs can download files
ex.printStackTrace(); ex.printStackTrace();
} }
} else if (status == JobStatus.DOWNLOAD) { } else if (status == JobStatus.DOWNLOAD) {
try { try {
// Obtain the CityGML file handle
File file = job.getResult(); File file = job.getResult();
assertTrue(file.canRead());
System.out.println("CityGML at " + file.getAbsolutePath()); System.out.println("CityGML at " + file.getAbsolutePath());
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
// Download may have failed
ex.printStackTrace(); ex.printStackTrace();
} }
} }
......
package eu.simstadt.nf4j.async.test;
import static org.junit.Assert.assertTrue;
import java.io.File;
import org.junit.Test;
import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.InvalidJobDescriptorException;
import eu.simstadt.nf4j.JobStatus;
import eu.simstadt.nf4j.async.AsyncImportJob;
import eu.simstadt.nf4j.async.HTTPConnection;
import eu.simstadt.nf4j.async.ImportJobDescription;
import eu.simstadt.nf4j.async.JobStatusEvent;
import eu.simstadt.nf4j.async.JobStatusListener;
/**
* This class contains client oriented import job tests. It will send an import job and listens to
* status updates. Every of the subsequent status' LOCAL, SENT, PENDING, RUNNING, FINISHED
* have to be signaled to this test class.
*
* @author Marcel Bruse
*/
public class SuccessfulImportJob implements JobStatusListener {
public AsyncImportJob job;
@Test
public void processJob() throws InterruptedException {
ImportJobDescription desc = ImportJobDescription.getDefaultDescriptor();
desc.setProduct("LBTEST");
desc.setLeaf("GR");
desc.setCityGMLFile(new File("SomeBuildings.gml"));
HTTPConnection connector = new HTTPConnection("193.196.136.164");
job = new AsyncImportJob(desc, connector);
job.addJobStatusListener(this);
try {
job.send();
} catch (InvalidJobDescriptorException ex) {
ex.printStackTrace();
} catch (FailedTransmissionException ex) {
ex.printStackTrace();
}
// Wait for timeout, failure or that all tests pass
long timeout = 1000 * 60 * 5l; // 5 minutes maximum
long interval = 10000l;
while (!job.hasFinished() && !job.hasFailed() && timeout > 0) {
Thread.sleep(interval);
timeout -= interval;
}
}
@Override
public void jobStatusChanged(JobStatusEvent event) {
JobStatus status = (JobStatus) event.getSource();
System.out.println(status);
if (status == JobStatus.LOCAL) {
assertTrue(true);
} else if (status == JobStatus.SENT) {
assertTrue(true);
} else if (status == JobStatus.PENDING) {
assertTrue(true);
} else if (status == JobStatus.RUNNING) {
assertTrue(true);
} else if (status == JobStatus.FINISHED) {
assertTrue(true);
}
}
}
\ No newline at end of file
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