Commit f1a210af authored by Eric Duminil's avatar Eric Duminil
Browse files

RegionChooser: Remove novafactory code

parent 6d96f1b5
package eu.simstadt.nf4j;
import java.io.File;
/**
* NFConnector lets you communicate with your novaFACTORY (nF) server instance.
*
* @param <I> The import job implementation which can be handled by the connector.
* @param <E> The export job implementation which can be handled by the connector.
*
* @author Marcel Bruse
*/
public interface Connector<I extends ImportJob<?>, E extends ExportJob<?>> {
/**
* 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 various NovaFACTORY interfaces may change over time. Such changes force the SimStadt programmers to
* implement different versions of this NFConnector interface while keeping old implementations due to
* backward compatibility.
*
* @return The supported version of the novaFACTORY.
*/
public String supportsNFVersion();
/**
* Sends an export job to nF. The job has to be passed to the nF in an appropriate XML job file.
* The DTD of the XML format can be obtained from the nF installation or documentation.
* The contents of the XML job file are detailed in the job's descriptor instance. This method is supposed to
* update the status of the job and the job id.
*
* @param job The nF export job with description. If the job description is invalid, you will receive an
* InvalidJobDescriptorException.
*/
public void sendAndUpdateExportJob(E exportJob)
throws InvalidJobDescriptorException, FailedTransmissionException;
/**
* Sends an import job to nF. A given import job descriptor has to describe the import job file. This
* method has to build the file and to zip it. The zip file 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
*
* <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 to be sent 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
*
* @param job The nF import job to be sent. It has to contain a valid description.
*/
public void sendAndUpdateImportJob(I importJob)
throws InvalidJobDescriptorException, FailedTransmissionException;
/**
* Returns the status of any existing export nF job.
*
* @param jobId The id of the export job for which you want to request the status.
* @return The status of any existing export nF job.
*/
public E requestExportJob(int jobId) throws FailedTransmissionException;
/**
* Returns the status of any existing import nF job.
*
* @param jobId The id of the import job for which you want to request the status.
* @return The status of any existing import nF job.
*/
public I requestImportJob(int jobId) throws FailedTransmissionException;
/**
* Downloads the result for a given nF export job and hands over the corresponding file handle.
*
* @param jobId The id of the export job for which the result should be loaded.
* @return A file handle to the result of the nF export job.
*/
public File requestExportJobResult(E exportJob) throws FailedTransmissionException;
}
package eu.simstadt.nf4j;
import java.io.File;
/**
* An export job is a proxy object for an actual nF export job. Export jobs are used to get data from your nF server.
* Every export job has to have a valid job descriptor and/or a job id.
*
* @author Marcel Bruse
*
* @param <D> The descriptor type for the export job implementation.
*/
public abstract class ExportJob<D extends ExportJobDescriptor> extends Job {
/** Every job should have a (valid) job descriptor. */
protected D descriptor;
/**
* This constructor forces the job to have a description and a connector instance.
*
* @param connector The job will use this connector to synchronize itself with the nF.
* @param descriptor The description of this job.
*/
public ExportJob(D descriptor, Connector<?, ?> connector) {
this.descriptor = descriptor;
this.connector = connector;
}
/**
* This constructor forces the job to have a id and a connector instance.
*
* @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 ExportJob(int id, Connector<?, ?> connector) {
this.id = id;
this.connector = connector;
}
/**
* @return Returns the description of this job.
*/
public D getDescriptor() {
return descriptor;
}
/**
* Once an export job has been finished, the caller should use this method to obtain the actual CityGML file.
*
* @return A file handle to the resulting CityGML file.
* @throws FailedTransmissionException There could be a problem while accessing or downloading the file.
*/
public abstract File getResult() throws FailedTransmissionException;
}
package eu.simstadt.nf4j;
/**
* Implementations of this interface are known to be export job descriptions.
*
* @author Marcel Bruse
*/
public interface ExportJobDescriptor extends JobDescriptor {}
package eu.simstadt.nf4j;
import java.io.File;
import java.util.ArrayList;
import javafx.application.Platform;
import netscape.javascript.JSObject;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import eu.simstadt.nf4j.async.AsyncExportJob;
import eu.simstadt.nf4j.async.Coord;
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;
/**
* 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
*/
//TODO: DRY with SuccessfulExportJob
public class ExportJobFromJavaFXRegionChooser implements JobStatusListener
{
public AsyncExportJob job;
private JSObject novaFactoryOpenLayer;
public void processJob(Geometry poly, String productName, JSObject novaFactoryOpenLayer) throws InterruptedException {
this.novaFactoryOpenLayer = novaFactoryOpenLayer;
ExportJobDescription description = ExportJobDescription.getDefaultDescriptor();
description.setInitiator(String.valueOf((int) (Math.random() * 9999)));
String userName = System.getProperty("user.name");
description.setAccount(userName);
// description.setProduct("WU3");
description.setProduct(productName);
description.setJobnumber(userName);
ArrayList<Coord> regionPolygon = new ArrayList<>();
for (Coordinate point : poly.getCoordinates()) {
regionPolygon.add(new Coord(point.y, point.x));
}
description.setRegionPolygon(regionPolygon);
Layer layer = Layer.getDefaultLayer();
layer.setProduct(productName);
layer.setName("GML");
description.addLayer(layer);
job = new AsyncExportJob(description, new HTTPConnection("193.196.136.164"));
job.addJobStatusListener(this);
try {
job.send();
} catch (FailedTransmissionException ex) {
ex.printStackTrace();
} catch (InvalidJobDescriptorException ex) {
ex.printStackTrace();
}
}
@Override
public void jobStatusChanged(JobStatusEvent event) {
JobStatus status = (JobStatus) event.getSource();
// System.out.println(status);
if (status == JobStatus.LOCAL) {
novaFactoryOpenLayer.call("updateStatus", "REQUEST HAS BEEN PREPARED");
} else if (status == JobStatus.SENT) {
novaFactoryOpenLayer.call("updateStatus", "REQUEST HAS BEEN SENT");
} else if (status == JobStatus.PENDING) {
novaFactoryOpenLayer.call("updateStatus", "PENDING");
} else if (status == JobStatus.RUNNING) {
novaFactoryOpenLayer.call("updateStatus", "SERVER IS BUSY");
} else if (status == JobStatus.FINISHED) {
try {
novaFactoryOpenLayer.call("updateStatus", "SERVER IS DONE");
job.downloadResult();
} catch (FailedTransmissionException ex) {
ex.printStackTrace();
}
} else if (status == JobStatus.DOWNLOAD) {
try {
File file = job.getResult();
novaFactoryOpenLayer.call("updateStatus", "DOWNLOADED AS ZIP");
//TODO: Call downloadFinished if FAILED
Platform.runLater(new Runnable() {
@Override
public void run() {
novaFactoryOpenLayer.call("selectSaveFile", file.toString());
}
});
novaFactoryOpenLayer.call("downloadFinished");
} catch (FailedTransmissionException ex) {
ex.printStackTrace();
}
}
}
}
\ No newline at end of file
package eu.simstadt.nf4j;
/**
* This exception may be thrown by classes of the nf4j package if/on ...
*
* - the connector is null
* - malformed URLs
* - missing or malformed XML reports
* - HTTP failures
*
* @author Marcel Bruse
*/
public class FailedTransmissionException extends Exception {
private static final long serialVersionUID = -3530932388888249528L;
/** An textual description of the error. */
private String message;
/** Standard constructor. */
public FailedTransmissionException() {}
/**
* Constructor with error message and without nested cause.
*
* @param message The error message.
*/
public FailedTransmissionException(String message) {
this(message, null);
}
/**
* Constructor with cause and without error message.
*
* @param cause The nested cause of this exception.
*/
public FailedTransmissionException(Throwable cause) {
this(null, cause);
}
/**
* Constructor with error message and nested cause.
*
* @param message The error message.
* @param cause The nested cause of this exception.
*/
public FailedTransmissionException(String message, Throwable cause) {
this.message = message;
initCause(cause);
}
/**
* @return Returns the error message, if present.
*/
@Override
public String getMessage() {
return message;
}
}
package eu.simstadt.nf4j;
/**
* An import job is a proxy object for an actual nF import job. Import jobs are used to store data in your nF database.
* Every import job has to have a valid job descriptor and/or a job id.
*
* @author Marcel Bruse
*
* @param <D> The descriptor type for the import job implementation.
*/
public abstract class ImportJob<D extends ImportJobDescriptor> extends Job {
/** Every job should have a (valid) job descriptor. */
protected D descriptor;
/**
* This constructor forces the job to have a description and a connector instance.
*
* @param connector The job will use this connector to synchronize itself with the nF.
* @param descriptor The description of this job.
*/
public ImportJob(D descriptor, Connector<?, ?> connector) {
this.descriptor = descriptor;
this.connector = connector;
}
/**
* This constructor forces the job to have a id and a connector instance.
*
* @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 ImportJob(int id, Connector<?, ?> connector) {
this.id = id;
this.connector = connector;
}
/**
* @return Returns the description of this job.
*/
public D getDescriptor() {
return descriptor;
}
}
package eu.simstadt.nf4j;
import java.io.File;
/**
* Implementations of this interface are known to implement import job descriptions.
*
* @author Marcel Bruse
*/
public interface ImportJobDescriptor extends JobDescriptor {
/**
* Sets the CityGML file which is supposed to be imported by the nF.
*
* @param file The CityGML file which is supposed to be imported by the nF.
*/
public void setCityGMLFile(File file);
/**
* @return Returns the CityGML file which is supposed to be imported by the nF.
*/
public File getCityGMLFile();
}
package eu.simstadt.nf4j;
/**
* If your export and import job descriptions are invalid due to the job.isValid() method, then it is very likely
* that you will get this exception.
*
* @author Marcel Bruse
*/
public class InvalidJobDescriptorException extends Exception {
private static final long serialVersionUID = 2710340003578550634L;
}
package eu.simstadt.nf4j;
/**
* This job class bundles the three attributes of every nF job: Id, status and last job related nF (error) message.
*
* @author Marcel Bruse
*/
public abstract class Job {
/** The status of the job. There are different states for export and import jobs. */
protected JobStatus status;
/** The id of the job. */
protected int id;
/** The connection to the nF. */
protected Connector<?, ?> connector;
/**
* 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.
*/
public JobStatus getStatus() {
return status;
}
/**
* Lets you set the status of this job.
*
* @param status The status of this job.
*/
protected void setStatus(JobStatus status) {
this.status = status;
}
/**
* @return Returns the id of this job.
*/
public int getId() {
return id;
}
/**
* Sets the id of this job.
*
* @param jobId The job id about to be set.
*/
public void setId(int jobId) {
this.id = jobId;
}
/**
* @return Returns the nF connector of this job.
*/
public Connector<?, ?> getConnector() {
return connector;
}
/**
* Sets the nF connector of this job.
*
* @param nFConnector The connector of this job.
*/
public void setConnector(Connector<?, ?> connector) {
this.connector = connector;
}
/**
* This method reads the job description, builds a job file from it and uses the connector to send the
* job file to nF. You may want to implement the file building and file sending parts in the
* connector in order to reuse them here.
*
* This method is a object oriented convenience method for NFConnector.sendXXXJobFile(). It is sensible
* to have this convenience method, because it offers the API user centralized controls over the jobs
* status chain without switching between job instances and connector instances. In the end, the user is
* not interested in the connection to the nF, but in the job itself.
*/
public abstract void send() throws InvalidJobDescriptorException, FailedTransmissionException;
/**
* Connects to the nF and refreshes the status of this job. If there is no nF connector set, or the job id
* is unkown by the nF, then this operation will throw a FailedTransmissionException.
*
* @throws FailedTransmissionException If the connection to the nF is broken you will get some of this.
*/
public abstract void updateStatus() 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. Export jobs and import jobs have different states. Consider this fact
* in your implementation.
*
* @param statusCode The nF status code for this job.
*/
public abstract void setStatusForCode(int statusCode);
}
package eu.simstadt.nf4j;
/**
* Every instance of this class describes an export or import job for the novaFACTORY. Instances of JobBuilder
* take JobDescriptions and build XML export and import job files out of it.
*
* @author Marcel Bruse
*/
public interface JobDescriptor {
/**
* @return The supported version of the XML import or export job format.
*/
public String supportsJobVersion();
/**
* @return Returns true, if the job description is complete and correct. False, otherwise.
*/
public boolean isValid();
}
package eu.simstadt.nf4j;
/**
* The list of all possible export and import job states.
*
* @author Marcel Bruse
*/
public enum JobStatus {
UNKNOWN(0), // A local NF4J code, may be set in rare cases, if synchronization with nF fails.
LOCAL(10), // Job has not been sent yet and is known by the local system only.
SENT(20), // Job has been sent or it is assumed that it has been set before.
PENDING(30), // Export job has been enqueued and waits for execution
READY_TO_RUN(31), // Same as PENDING, but for import jobs
APPROVE(32), // (?) For import jobs only. Read the nF documentation, seams to be never used.
RUNNING(40), // Job is running
APPROVE_RUNNING(41), // (?) For import jobs only. Read the nF documentation, seams to be never used.
FAILED(50), // Export job failed
ERROR(51), // Same as FAILED, but for import jobs
WARNING(52), // For import jobs only. There has been a minor problem
REJECT(53), // (?) For import jobs only. Read the nF documentation, seams to be never used.
REJECT_RUNNING(54), // (?) For import jobs only. Read the nF documentation, seams to be never used.
APPROVE_REJECT_ERROR(55), // (?) For import jobs only. Read the nF documentation, seams to be never used.
APPROVE_REJECT_OK(56), // (?) For import jobs only. Read the nF documentation, seams to be never used.
IMPORTED_WARNING(57), // (?) For import jobs only. Read the nF documentation, seams to be never used.
FINISHED(60), // Job finished
DOWNLOAD(70); // Export jobs only. CityGML has been download to the local file system
public static final String UNKNOWN_MESSAGE = "The state of the job is unknown.";
public static final String LOCAL_MESSAGE = "The job is known locally only. It has not been sent yet.";
public static final String SENT_MESSAGE = "The job has been sent, is enqueued at the nF and has a job id.";
public static final String PENDING_MESSAGE = "Job is pending.";
public static final String RUNNING_MESSAGE = "Job is running.";
public static final String FAILED_MESSAGE = "Job failed.";
public static final String FINISHED_MESSAGE = "Job is finished.";
public static final String WAITING_MESSAGE = "Job is waiting for a response from the remote nF instance.";
/**
* This constructor sets messages for some states.
*
* @param internalCode Our numerical SimStadt-internal code for the nF status codes.
*/
private JobStatus(int internalCode) {
switch (internalCode) {
case 0:
message = UNKNOWN_MESSAGE; break;
case 10:
message = LOCAL_MESSAGE; break;
case 20:
message = SENT_MESSAGE; break;
case 30:
case 31:
message = PENDING_MESSAGE; break;
case 40:
message = RUNNING_MESSAGE; break;
case 50:
case 51:
message = FAILED_MESSAGE; break;
case 60:
message = FINISHED_MESSAGE; break;
default:
message = "";
}
}
/**
* This message describes the status or gives hints about error states. This message may come from a
* nF response.
*/
private String message;
/**
* Sets a message for this status in order to describe the status.
*
* @param message A message to describe this status.
*/
public void setMessage(String message) {
this.message = message;
}
/**
* @return Returns a message which describes this status.
*/
public String getMessage() {
return message;
}
}
package eu.simstadt.nf4j.async;
import java.io.File;
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;
/**
* 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.
*
* @author Marcel Bruse
*/
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.
*/
private final int DEFAULT_POLLING_INTERVAL = 5; // seconds
/** There can only be one sending thread for each job at a time. */
private Thread sendThread;
/** There can only be one polling thread for each job at a time. */
private Thread pollThread;
/** There can only be one download thread for each job at a time. */
private Thread downloadThread;
/**
* 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;
/** As long as this variable is true, the polling thread will be kept alive. */
private boolean keepPolling = true;
/**
* 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. 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();
/**
* The last job status which has been sent to all registered job status listeners.
*/
private JobStatus lastPublishedJobStatus;
/** Once the CityGML file has been download, it should be referenced here. */
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.
*
* @param connector The job will use this connector to synchronize itself with the nF.
* @param descriptor The description of this job.
*/
public AsyncExportJob(ExportJobDescription descriptor, Connector<AsyncImportJob, AsyncExportJob> connector) {
super(descriptor, connector);
status = JobStatus.LOCAL;
}
/**
* 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.
*
* @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) {
super(id, connector);
status = JobStatus.SENT;
}
/**
* 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.
*/
@Override
public synchronized void send() throws FailedTransmissionException, InvalidJobDescriptorException {
if (jobTransmissionTriggered) {
throw new FailedTransmissionException("Jobs cannot be sent twice!");
}
if (Objects.isNull(descriptor) || !descriptor.isValid()) {
throw new InvalidJobDescriptorException();
}
jobTransmissionTriggered = true;
notifyJobStatusListeners(); // Force the job to signal the LOCAL status
sendThread = new Thread(new SendExportJobTask(this));
sendThread.start();
}
/**
* 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.
*/
@Override
public synchronized void poll(int interval) throws FailedTransmissionException {
if (status.compareTo(JobStatus.SENT) < 0) {
throw new FailedTransmissionException("The job has not been sent to the nF yet!");
}
if (Objects.nonNull(pollThread)) {
pollThread.interrupt();
}
keepPolling = true;
pollThread = new Thread(new PollJobStatusTask(this, interval));
pollThread.start();
}
/**
* 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)
*/
public synchronized void poll() throws FailedTransmissionException {
poll(DEFAULT_POLLING_INTERVAL);
}
/**
* 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".
*/
@Override
public synchronized void updateStatus() throws FailedTransmissionException {
if (Objects.isNull(connector)) {
throw new FailedTransmissionException("No connector set for this job!");
}
if (status.compareTo(JobStatus.SENT) < 0) {
throw new FailedTransmissionException("The job has not been sent to the nF yet!");
}
AsyncExportJob job = ((HTTPConnection) connector).requestExportJob(id);
JobStatus newStatus = job.getStatus();
if (newStatus.compareTo(JobStatus.SENT) > 0) {
setStatus(job.getStatus(), Optional.empty());
}
}
/**
* 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 {
updateStatus();
}
/**
* 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.
*/
@Override
public synchronized void setStatusForCode(int statusCode) {
switch (statusCode) {
case 0:
setStatus(JobStatus.PENDING);
break;
case 10:
setStatus(JobStatus.RUNNING);
break;
case 20:
setStatus(JobStatus.FAILED);
break;
case 30:
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.
*/
@Override
public boolean hasFinished() {
return status == JobStatus.FINISHED || status == JobStatus.DOWNLOAD;
}
/**
* @return Returns true, if the job has been failed. You may want to look up the "last encountered problem" string.
*/
@Override
public boolean hasFailed() {
return status == JobStatus.FAILED;
}
/**
* 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.
*/
@Override
public void addJobStatusListener(JobStatusListener jobListener) {
jobListenerList.add(jobListener);
}
/**
* Unregisters a job status listener.
*
* @param jobListener The job status listener to be unregistered.
*/
@Override
public void removeJobStatusListener(JobStatusListener jobListener) {
jobListenerList.remove(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.
*/
@Override
public synchronized void notifyJobStatusListeners() {
if (Objects.isNull(lastPublishedJobStatus) || status.compareTo(lastPublishedJobStatus) > 0) {
JobStatusEvent event = new JobStatusEvent(status, this, lastEncounteredProblem);
for (JobStatusListener listener : jobListenerList) {
listener.jobStatusChanged(event);
}
lastPublishedJobStatus = status;
}
}
/**
* Cancels all ongoing send, poll and download operations as soon as possible.
*/
@Override
public void cancel() {
keepPolling = false;
if (Objects.nonNull(sendThread)) {
sendThread.interrupt();
}
if (Objects.nonNull(pollThread)) {
pollThread.interrupt();
}
if (Objects.nonNull(downloadThread)) {
downloadThread.interrupt();
}
}
/**
* @return Returns true, if the polling thread should go on with its polling job. Otherwise, false.
*/
@Override
public boolean keepPolling() {
return 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().
*
* @throws FailedTransmissionException If the job has not been finished yet, then you will get some of this.
*/
public void downloadResult() throws FailedTransmissionException {
if (!hasFinished()) {
throw new FailedTransmissionException("Job has not been finished!");
}
downloadThread = new Thread(new DownloadTask(this));
downloadThread.start();
}
/**
* 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.
*/
protected void setResult(File result) {
this.result = result;
}
/**
* 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.
*/
@Override
public File getResult() throws FailedTransmissionException {
if (!hasFinished()) {
throw new FailedTransmissionException("Job has not been finished!");
}
if (Objects.isNull(result)) {
throw new FailedTransmissionException("Job result has not been downloaded!");
}
return result;
}
/**
* 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.
*
* @param errorMessage The description of the encountered problem. This could be the exception message or a more user
* friendly message.
*/
protected synchronized void setLastEncounteredProblem(Optional<String> errorMessage) {
this.lastEncounteredProblem = errorMessage;
}
/**
* A convenience method to set a new job status and a status message at the same time. Status messages will be passed
* by asynchronous tasks instead of exception, because they cannot throw exceptions.
*
* @param jobStatus The new status of this job.
* @param message A status message. This message may describe a problem which occurred during an asynchronous task.
*/
protected synchronized void setStatus(JobStatus jobStatus, Optional<String> message) {
super.setStatus(jobStatus);
lastEncounteredProblem = message;
notifyJobStatusListeners();
}
}
\ No newline at end of file
package eu.simstadt.nf4j.async;
import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import eu.simstadt.nf4j.ImportJob;
import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.InvalidJobDescriptorException;
import eu.simstadt.nf4j.JobStatus;
/**
* Import jobs are requests to store, change or delete CityGML models. Every valid import job has an id and a status.
* This implementation offers non-blocking asynchronous send and poll 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 AsyncImportJob extends ImportJob<ImportJobDescription> implements AsyncJob {
/**
* 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
private boolean jobTransmissionTriggered = false;
private JobStatus lastPublishedJobStatus;
private Optional<String> lastEncounteredProblem = Optional.empty();
private Thread sendThread;
private Thread pollThread;
/** As long as this variable is true, the polling thread will be kept alive. */
private boolean keepPolling = true;
/**
* 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 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.
*/
public AsyncImportJob(ImportJobDescription descriptor, HTTPConnection connector) {
super(descriptor, connector);
status = JobStatus.LOCAL;
}
/**
* 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.
*
* @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 AsyncImportJob(int id, HTTPConnection connector) {
super(id, connector);
status = JobStatus.SENT;
}
/**
* This method zips up an archive which includes the CityGML file to be imported as well as a nF start
* file. Both files will be preprocessed according to the set attributes of the job description.
*/
@Override
public synchronized void send() throws InvalidJobDescriptorException, FailedTransmissionException {
if (jobTransmissionTriggered) {
throw new FailedTransmissionException("Jobs cannot be sent twice!");
}
if (Objects.isNull(descriptor) || !descriptor.isValid()) {
throw new InvalidJobDescriptorException();
}
jobTransmissionTriggered = true;
notifyJobStatusListeners(); // Force the job to signal the LOCAL status
sendThread = new Thread(new SendImportJobTask(this));
sendThread.start();
}
/**
* 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
* upon every new status change.
*
* @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.
*/
@Override
public synchronized void poll(int interval) throws FailedTransmissionException {
if (status.compareTo(JobStatus.SENT) < 0) {
throw new FailedTransmissionException("The job has not been sent to the nF yet!");
}
if (Objects.nonNull(pollThread)) {
pollThread.interrupt();
}
keepPolling = true;
pollThread = new Thread(new PollJobStatusTask(this, interval));
pollThread.start();
}
/**
* Convenience method for polling with a predefined default interval.
*
* @see poll(int)
*/
public synchronized void poll() throws FailedTransmissionException {
poll(DEFAULT_POLLING_INTERVAL);
}
/**
* 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 If the connection to the nF is broken you will get some of this.
*/
@Override
public synchronized void updateStatus() throws FailedTransmissionException {
if (Objects.nonNull(connector)) {
AsyncImportJob job = ((HTTPConnection) connector).requestImportJob(id);
JobStatus newStatus = job.getStatus();
if (newStatus.compareTo(JobStatus.SENT) > 0) {
setStatus(job.getStatus(), Optional.empty());
}
} else {
throw new 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. Note, the nF status code differ from the internal job status codes of
* this library. Read the nF documentation for more information.
*
* @param statusCode The nF status code for this job.
*/
@Override
public synchronized void setStatusForCode(int statusCode) {
switch (statusCode) {
case 0:
setStatus(JobStatus.PENDING); break;
case 10:
setStatus(JobStatus.RUNNING); break;
case 20:
setStatus(JobStatus.ERROR); break;
case 25:
setStatus(JobStatus.WARNING); break;
case 30:
setStatus(JobStatus.FINISHED); break;
case 40:
setStatus(JobStatus.APPROVE); break;
case 45:
setStatus(JobStatus.REJECT); break;
case 50:
setStatus(JobStatus.APPROVE_RUNNING); break;
case 55:
setStatus(JobStatus.REJECT_RUNNING); break;
case 60:
setStatus(JobStatus.APPROVE_REJECT_ERROR); break;
case 70:
setStatus(JobStatus.APPROVE_REJECT_OK); break;
case 80:
setStatus(JobStatus.IMPORTED_WARNING); break;
default:
setStatus(JobStatus.UNKNOWN);
}
}
/**
* 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.
*/
@Override
public void addJobStatusListener(JobStatusListener jobListener) {
jobListenerList.add(jobListener);
}
/**
* Unregisters a job status listener.
*
* @param jobListener The job status listener to be unregistered.
*/
@Override
public void removeJobStatusListener(JobStatusListener jobListener) {
jobListenerList.remove(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.
*/
@Override
public synchronized void notifyJobStatusListeners() {
if (Objects.isNull(lastPublishedJobStatus) || status.compareTo(lastPublishedJobStatus) > 0) {
JobStatusEvent event = new JobStatusEvent(status, this, lastEncounteredProblem);
for (JobStatusListener listener : jobListenerList) {
listener.jobStatusChanged(event);
}
lastPublishedJobStatus = status;
}
}
/**
* A convenience method to set a new job status and a status message at the same time. Status messages will be passed
* by asynchronous tasks instead of exception, because they cannot throw exceptions.
*
* @param jobStatus The new status of this job.
* @param message A status message. This message may describe a problem which occurred during an asynchronous task.
*/
protected synchronized void setStatus(JobStatus jobStatus, Optional<String> message) {
super.setStatus(jobStatus);
lastEncounteredProblem = message;
notifyJobStatusListeners();
}
/**
* Cancels all ongoing send and poll operations as soon as possible.
*/
@Override
public void cancel() {
keepPolling = false;
if (Objects.nonNull(sendThread)) {
sendThread.interrupt();
}
if (Objects.nonNull(pollThread)) {
pollThread.interrupt();
}
}
/**
* @return Returns true, if the polling thread should go on with its polling job. Otherwise, false.
*/
@Override
public boolean keepPolling() {
return keepPolling;
}
/**
* @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() {
return status == JobStatus.FINISHED;
}
/**
* @return Returns true, if the job has been failed. You may want to look up the "last encountered problem"
* string.
*/
@Override
public boolean hasFailed() {
return status == JobStatus.FAILED || status == JobStatus.ERROR;
}
/**
* 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 {
updateStatus();
}
}
\ No newline at end of file
package eu.simstadt.nf4j.async;
import eu.simstadt.nf4j.FailedTransmissionException;
/**
* An asynchronous job will be sent in a non-blocking fashion, so that the main thread can proceed after calling
* the send() operation. It queries the status of its remote nF counterpart frequently in a separate thread, so that
* the job operations don't have to wait. Every asynchronous job should maintain a list of job status listeners.
* Every registered job status listener should be notified upon significant and new job status changes.
*
* @author Marcel Bruse
*/
public interface AsyncJob {
/**
* 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
* upon every new status change.
*
* @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.
*/
public void poll(int interval) throws FailedTransmissionException;
/**
* Cancels all ongoing asynchronous operations of this job as soon as possible. Operations to be canceled
* might be send, poll and download operations.
*/
public void cancel();
/**
* Registers a job status listener at this job. The listener will then be notified upon job status changes.
*
* @param jobListener The job status listener to be registered at this job.
*/
public void addJobStatusListener(JobStatusListener jobListener);
/**
* Unregisters a job status listener for this job. The listener will not be notified about job status changes
* anymore.
*
* @param jobListener The job status listener to be unregistered.
*/
public void removeJobStatusListener(JobStatusListener jobListener);
/**
* Once the status of this job changes, all registered job status listeners will be notified.
*/
public void notifyJobStatusListeners();
/**
* Convenience method.
*
* @return Returns true, if the job is definitely done.
*/
public boolean hasFinished();
/**
* Convenience method.
*
* @return Returns true, if the job was unable to recover from a serious problem.
*/
public boolean hasFailed();
/**
* Asynchronous polling tasks may query this flag frequently in order to decide to proceed or not.
*
* @return Returns true, if the polling task should continue polling for status updates.
*/
public boolean keepPolling();
/**
* Calls updateStatus() for you, since updateStatus() is a protected method. This method is used by the
* asynchronous PollJobStatusTask class.
*
* @throws FailedTransmissionException If something goes wrong during the update process, you will get some
* of this.
*/
public void triggerStatusUpdate() throws FailedTransmissionException;
}
package eu.simstadt.nf4j.async;
/**
* This enumeration lists some of the "well known texts" (WKT) which are used to identify
* coordinate reference systems (CRS).
*
* @author Marcel Bruse
*
*/
public enum CRSWKT {
EPSG_31467("EPSG:31467"), // DHDN Gauss-Kruger zone 3
EPSG_4326("EPSG:4326"); // WGS 84
/** The well known texts for a CRS. */
public String wkt;
/** Constructor for well known texts. */
private CRSWKT(String wkt) {
this.wkt = wkt;
}
}
package eu.simstadt.nf4j.async;
/**
* Another class for coordinates. Is there a general purpose class for this kind of applications?
* This might be an intermediate representation for WGS 84 coordinates.
*
* @author Marcel Bruse
*/
public class Coord {
/** The latitude of the geographic position. */
public double latitude;
/** The longitude of the geographic position. */
public double longitude;
/** Standard constructor.
*
* @param latitude The latitude of the WGS 84 coordinate.
* @param longitude The longitude of the WGS 84 coordinate.
*/
public Coord(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
}
package eu.simstadt.nf4j.async;
import java.io.File;
import java.util.Optional;
import eu.simstadt.nf4j.FailedTransmissionException;
import eu.simstadt.nf4j.JobStatus;
/**
* This task downloads export job results asynchronously within its jobs separate download thread.
* You can cancel this task by calling job.cancel().
*
* @author Marcel Bruse
*/
public class DownloadTask implements Runnable {
/** The finished export job for which you want to download a CityGML result. */
private AsyncExportJob job;
/**
* Constructor with finished(!) asynchronous export job.
*
* @param job The export job for which you want to download the CityGML result.
*/
public DownloadTask(AsyncExportJob job) {
this.job = job;
}
/**
* This method performs the download operation asynchronously in the export jobs download thread.
* Job status listeners will be notified upon the finished download.
*/
@Override
public void run() {
HTTPConnection connector = (HTTPConnection) job.getConnector();
try {
File file = connector.requestExportJobResult(job);
job.setResult(file);
job.setStatus(JobStatus.DOWNLOAD, Optional.empty());
} catch (FailedTransmissionException ex) {
// Conditions have been checked by main thread. No exception handling needed.
}
}
}
package eu.simstadt.nf4j.async;
import java.util.ArrayList;
import java.util.List;
import eu.simstadt.nf4j.ExportJobDescriptor;
/**
* Every instance of this class describes an export job for the novaFACTORY. Instances of JobBuilder
* take JobDescriptions and build XML export job files out of it.
*
* @author Marcel Bruse
*/
public class ExportJobDescription implements ExportJobDescriptor {
private static final String DEFAULT_ACCOUNT = "Marcel";
private static final String DEFAULT_XMETA_DATA = "0";
private static final String DEFAULT_CALIBRATION = "0";
private static final String DEFAULT_PRODUCT = "WUDEV";
private static final String DEFAULT_ZIP_RESULT = "0";
private static final String DEFAULT_DHK_RESOLVE_REFERENCES = "1";
private static final String DEFAULT_USE_PDCT_BORDER_POLY = "0";
private static final String DEFAULT_USE_NO_DATA_MASK = "0";
private static final String DEFAULT_ECK = "0";
private static final String DEFAULT_COL = "0";
private static final String DEFAULT_EXPORT_META_DATA = "1";
private static final String DEFAULT_FORMAT = "CityGML";
private static final String DEFAULT_SCALE = "10000.0";
private static final String DEFAULT_RESOLUTION = "100.0";
private static final String DEFAULT_MERGE_MAP_SHEETS = "off";
private static final String DEFAULT_TILE1ASGN = "false";
private static final String DEFAULT_SRS = "31467";
private static final String DEFAULT_SINGLE = "1";
private static final String DEFAULT_PLOTFRAME = "0";
private static final String DEFAULT_PLOT_LABEL_SRS = "-1";
private static final String DEFAULT_MONO = "0";
private static final String DEFAULT_COLOR = "0";
private static final String DEFAULT_JOBNUMBER = "GR_EXPORT_CITYGML_LOD1";
private static final String DEFAULT_INITIATOR = "2758";
private static final String DEFAULT_LODS = "12";
/** The version of the novaFACTORY XML export job format. */
public static final String EXPORT_JOB_VERSION = "1.0.0";
/** TODO: Who or what is this initiator? */
private String initiator;
/** The number of the job which can actually be a string. */
private String jobnumber;
/** The account or user for which a job should be executed. */
private String account;
/** The product for which a job should be executed. */
private String product;
/** Color attribute of the layers tag. */
private String color;
/** The mono attribute of the layers tag. */
private String mono;
/** The plotLabelSrs flag of the layers tag. */
private String plotLabelSrs;
/** The plotframe flag of the layers tag. */
private String plotframe;
/** The single flag of the layers tag. */
private String single;
/** The layers which will be involved in a job. */
private ArrayList<Layer> layerList = new ArrayList<>();
/** The SRS for the job. */
private String srs;
/** The merge_mapsheets attribute of the extent tag. */
private String mergeMapsheets;
/** The tile1asgn attribute of the extent tag. */
private String tile1asgn;
/** The unit tag of the extent. */
private ArrayList<Unit> unitList = new ArrayList<>();
/** The polygon of the selected region which should be exported. */
ArrayList<Coord> regionPolygon = new ArrayList<>();
/** The resolution for the job. */
private String resolution;
/** The scale for the job. */
private String scale;
/** The format for the job. E.g. CityGML. */
private String format;
/** The exportmetadata flag for the job. */
private String exportmetadata;
/** The col attribute of the addfile tag. */
private String col;
/** The eck attribute of the addfile tag. */
private String eck;
/** The usenodatamask flag for the job. */
private String usenodatamask;
/** The usepdctborderpoly flag for the job. */
private String usepdctborderpoly;
/** The dhkresolvereferences flag for the job. */
private String dhkresolvereferences;
/** Flag for zipped results. */
private String zipresult;
/** The calibration attribute of the exportmetadata tag. */
private String calibration;
/** The xmetadata attribute of the exportmetadata tag. */
private String xmetadata;
/** The LOD or LODs which should be exported. Set it to "1", if you want LOD1.
* Set it to "12", if you want the LOD1 and LOD2.
*/
private String lods;
public String getInitiator() {
return initiator;
}
public void setInitiator(String initiator) {
this.initiator = initiator;
}
public String getJobnumber() {
return jobnumber;
}
public void setJobnumber(String jobnumber) {
this.jobnumber = jobnumber;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getProduct() {
return product;
}
public void setProduct(String product) {
this.product = product;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getMono() {
return mono;
}
public void setMono(String mono) {
this.mono = mono;
}
public String getPlotLabelSrs() {
return plotLabelSrs;
}
public void setPlotLabelSrs(String plotLabelSrs) {
this.plotLabelSrs = plotLabelSrs;
}
public String getPlotframe() {
return plotframe;
}
public void setPlotframe(String plotframe) {
this.plotframe = plotframe;
}
public String getSingle() {
return single;
}
public void setSingle(String single) {
this.single = single;
}
public ArrayList<Layer> getLayerList() {
return layerList;
}
public void setLayerList(ArrayList<Layer> layerList) {
this.layerList = layerList;
}
public void addLayer(Layer layer) {
layerList.add(layer);
}
public String getSrs() {
return srs;
}
public void setSrs(String srs) {
this.srs = srs;
}
public String getMergeMapsheets() {
return mergeMapsheets;
}
public void setMergeMapsheets(String mergeMapsheets) {
this.mergeMapsheets = mergeMapsheets;
}
public ArrayList<Unit> getUnitList() {
return unitList;
}
public void addUnit(Unit unit) {
unitList.add(unit);
}
public String getTile1asgn() {
return tile1asgn;
}
public void setTile1asgn(String tile1asgn) {
this.tile1asgn = tile1asgn;
}
public String getResolution() {
return resolution;
}
public void setResolution(String resolution) {
this.resolution = resolution;
}
public String getScale() {
return scale;
}
public void setScale(String scale) {
this.scale = scale;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String getExportmetadata() {
return exportmetadata;
}
public void setExportmetadata(String exportmetadata) {
this.exportmetadata = exportmetadata;
}
public String getCol() {
return col;
}
public void setCol(String col) {
this.col = col;
}
public String getEck() {
return eck;
}
public void setEck(String eck) {
this.eck = eck;
}
public String getUsenodatamask() {
return usenodatamask;
}
public void setUsenodatamask(String usenodatamask) {
this.usenodatamask = usenodatamask;
}
public String getUsepdctborderpoly() {
return usepdctborderpoly;
}
public void setUsepdctborderpoly(String usepdctborderpoly) {
this.usepdctborderpoly = usepdctborderpoly;
}
public String getDhkresolvereferences() {
return dhkresolvereferences;
}
public void setDhkresolvereferences(String dhkresolvereferences) {
this.dhkresolvereferences = dhkresolvereferences;
}
public String getZipresult() {
return zipresult;
}
public void setZipresult(String zipresult) {
this.zipresult = zipresult;
}
public String getCalibration() {
return calibration;
}
public void setCalibration(String calibration) {
this.calibration = calibration;
}
public String getXmetadata() {
return xmetadata;
}
public void setXmetadata(String xmetadata) {
this.xmetadata = xmetadata;
}
public String getLODs() {
return lods;
}
public void setLODs(String lods) {
this.lods = lods;
}
@Override
public String supportsJobVersion() {
return EXPORT_JOB_VERSION;
}
/**
* Adds a new coordinate to the region polygon. A region polygon is only used for export jobs.
*
* @param coordinate The new coordiante of the region polygon of a export job.
*/
public void addCoordinateToRegionPolygon(Coord coordinate) {
regionPolygon.add(coordinate);
}
/**
* Sets the whole region polygon for an export job.
*
* @param regionPolygon The region polygon to be used for an export job.
*/
public void setRegionPolygon(List<Coord> regionPolygon) {
this.regionPolygon.clear();
this.regionPolygon.addAll(regionPolygon);
}
/**
* @return Returns the region polygon.
*/
public ArrayList<Coord> getRegionPolygon() {
return regionPolygon;
}
/**
* @return Returns true, if all mandatory elements and attributes are set. Otherwise, false.
*/
@Override
public boolean isValid() {
if ((regionPolygon.isEmpty() && (unitList.isEmpty()))
|| layerList.isEmpty()
|| initiator.isEmpty()
|| account.isEmpty()
|| jobnumber.isEmpty()
|| product.isEmpty()
|| color.isEmpty()
|| mono.isEmpty()
|| plotLabelSrs.isEmpty()
|| plotframe.isEmpty()
|| single.isEmpty()
|| srs.isEmpty()
|| resolution.isEmpty()
|| scale.isEmpty()
|| format.isEmpty()
|| exportmetadata.isEmpty()
|| col.isEmpty()
|| eck.isEmpty()
|| lods.isEmpty()) {
return false;
} else {
return true;
}
}
public static ExportJobDescription getDefaultDescriptor() {
ExportJobDescription descriptor = new ExportJobDescription();
descriptor.setInitiator(DEFAULT_INITIATOR);
descriptor.setJobnumber(DEFAULT_JOBNUMBER);
descriptor.setAccount(DEFAULT_ACCOUNT);
descriptor.setProduct(DEFAULT_PRODUCT);
descriptor.setColor(DEFAULT_COLOR);
descriptor.setMono(DEFAULT_MONO);
descriptor.setPlotLabelSrs(DEFAULT_PLOT_LABEL_SRS);
descriptor.setPlotframe(DEFAULT_PLOTFRAME);
descriptor.setSingle(DEFAULT_SINGLE);
descriptor.setSrs(DEFAULT_SRS);
descriptor.setMergeMapsheets(DEFAULT_MERGE_MAP_SHEETS);
descriptor.setTile1asgn(DEFAULT_TILE1ASGN);
descriptor.setResolution(DEFAULT_RESOLUTION);
descriptor.setScale(DEFAULT_SCALE);
descriptor.setFormat(DEFAULT_FORMAT);
descriptor.setExportmetadata(DEFAULT_EXPORT_META_DATA);
descriptor.setCol(DEFAULT_COL);
descriptor.setEck(DEFAULT_ECK);
descriptor.setUsenodatamask(DEFAULT_USE_NO_DATA_MASK);
descriptor.setUsepdctborderpoly(DEFAULT_USE_PDCT_BORDER_POLY);
descriptor.setDhkresolvereferences(DEFAULT_DHK_RESOLVE_REFERENCES);
descriptor.setZipresult(DEFAULT_ZIP_RESULT);
descriptor.setCalibration(DEFAULT_CALIBRATION);
descriptor.setXmetadata(DEFAULT_XMETA_DATA);
descriptor.setLODs(DEFAULT_LODS);
return descriptor;
}
}
This diff is collapsed.
package eu.simstadt.nf4j.async;
import java.io.File;
import java.util.ArrayList;
import java.util.Objects;
import eu.simstadt.nf4j.ImportJobDescriptor;
/**
* Every instance of this class describes an import job for the novaFACTORY. Instances of NFConnector and
* JobBuilder take JobDescriptions and build XML import job files out of it.
*
* @author Marcel Bruse
*/
public class ImportJobDescription implements ImportJobDescriptor {
/** The version of the novaFACTORY XML export job format. */
public static final String IMPORT_JOB_VERSION = "1.0.0";
/** The default level on which your CityGML will be stored within the nF. */
public static final String DEFAULT_LEVEL = "GML";
/** List of ADE XML schemata which describe additional elements within the CityGML file. */
private ArrayList<File> adeSchemaFileList = new ArrayList<>();
/** The nF product (Produkt) which will keep our CityGML. */
private String product;
/** The nF leaf (Blatt) of the nF product. */
private String leaf;
/** The nF level (Ebene) of the nF product. */
private String level;
/** The operation to be performed for the feature objects of the CityGML file. */
private Operation operation;
/** The CityGML file to be imported to the nF. */
private File cityGMLFile;
/**
* Sets the CityGML file which should be imported by nF.
*
* @param file The CityGML file to be uploaded to the nF.
*/
@Override
public void setCityGMLFile(File cityGMLFile) {
this.cityGMLFile = cityGMLFile;
}
/**
* @return Returns the CityGML file which should be uploaded to the nF.
*/
@Override
public File getCityGMLFile() {
return cityGMLFile;
}
/**
* @return Returns the nF product which will keep our CityGML.
*/
public String getProduct() {
return product;
}
/**
* Sets the nF product for this import job.
*
* @param product The product of our import job.
*/
public void setProduct(String product) {
this.product = product;
}
/**
* @return Returns the nF leaf of the nF product.
*/
public String getLeaf() {
return leaf;
}
/**
* Sets the nF leaf for the nF product.
*
* @param leaf The leaf for the nF product.
*/
public void setLeaf(String leaf) {
this.leaf = leaf;
}
/**
* @return Returns the level of the product.
*/
public String getLevel() {
return level;
}
/**
* Sets the nF level for the nF product.
*
* @param level The level for the nF product.
*/
public void setLevel(String level) {
this.level = level;
}
/**
* If your CityGML file encodes ADE specific elements then you have to add the corresponding schema
* definition file of the used ADE here.
*
* @param adeSchemaFile The schema definition of the used ADE.
*/
public void addADESchemaFile(File adeSchemaFile) {
adeSchemaFileList.add(adeSchemaFile);
}
/**
* @return Returns the list of ADE schemata which are used within your CityGML file.
*/
public ArrayList<File> getADESchemaFileList() {
return adeSchemaFileList;
}
/**
* @return Returns the operation which should be conducted for the features of the CityGML file.
*/
public Operation getOperation() {
return operation;
}
/**
* Sets the operation which should be conducted for the feature objects of the CityGML file.
*
* @param operation The operation which should be conducted for the feature object of the CityGML file.
*/
public void setOperation(Operation operation) {
this.operation = operation;
}
/**
* @return Returns the supported nF job version. This enables your job builder instance to check if
* the job version is compatible with itself.
*/
@Override
public String supportsJobVersion() {
return IMPORT_JOB_VERSION;
}
/**
* This is just a prototype for presentation purposes.
*/
public static ImportJobDescription getDefaultDescriptor() {
ImportJobDescription descriptor = new ImportJobDescription();
descriptor.setLevel(DEFAULT_LEVEL);
return descriptor;
}
/**
* @return Returns true, if product, leaf, level and CityGML file are present.
*/
public boolean isValid() {
if (product.isEmpty()
|| leaf.isEmpty()
|| level.isEmpty()
|| Objects.isNull(cityGMLFile)
|| !cityGMLFile.canRead()) {
return false;
} else {
return 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