Commit 5a0bec3d authored by eric.duminil's avatar eric.duminil
Browse files

Removing CRLF from repository.

parent 3f54801c
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import eu.simstadt.nf4j.ImportJobDescriptor; import eu.simstadt.nf4j.ImportJobDescriptor;
/** /**
* Every instance of this class describes an import job for the novaFACTORY. Instances of NFConnector and * 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. * JobBuilder take JobDescriptions and build XML import job files out of it.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class ImportJobDescription implements ImportJobDescriptor { public class ImportJobDescription implements ImportJobDescriptor {
/** The version of the novaFACTORY XML export job format. */ /** The version of the novaFACTORY XML export job format. */
public static final String IMPORT_JOB_VERSION = "1.0.0"; public static final String IMPORT_JOB_VERSION = "1.0.0";
/** The default level on which your CityGML will be stored within the nF. */ /** The default level on which your CityGML will be stored within the nF. */
public static final String DEFAULT_LEVEL = "GML"; public static final String DEFAULT_LEVEL = "GML";
/** List of ADE XML schemata which describe additional elements within the CityGML file. */ /** List of ADE XML schemata which describe additional elements within the CityGML file. */
private ArrayList<File> adeSchemaFileList = new ArrayList<>(); private ArrayList<File> adeSchemaFileList = new ArrayList<>();
/** The nF product (Produkt) which will keep our CityGML. */ /** The nF product (Produkt) which will keep our CityGML. */
private String product; private String product;
/** The nF leaf (Blatt) of the nF product. */ /** The nF leaf (Blatt) of the nF product. */
private String leaf; private String leaf;
/** The nF level (Ebene) of the nF product. */ /** The nF level (Ebene) of the nF product. */
private String level; private String level;
/** The operation to be performed for the feature objects of the CityGML file. */ /** The operation to be performed for the feature objects of the CityGML file. */
private Operation operation; private Operation operation;
/** The CityGML file to be imported to the nF. */ /** The CityGML file to be imported to the nF. */
private File cityGMLFile; private File cityGMLFile;
/** /**
* Sets the CityGML file which should be imported by nF. * Sets the CityGML file which should be imported by nF.
* *
* @param file The CityGML file to be uploaded to the nF. * @param file The CityGML file to be uploaded to the nF.
*/ */
@Override @Override
public void setCityGMLFile(File cityGMLFile) { public void setCityGMLFile(File cityGMLFile) {
this.cityGMLFile = cityGMLFile; this.cityGMLFile = cityGMLFile;
} }
/** /**
* @return Returns the CityGML file which should be uploaded to the nF. * @return Returns the CityGML file which should be uploaded to the nF.
*/ */
@Override @Override
public File getCityGMLFile() { public File getCityGMLFile() {
return cityGMLFile; return cityGMLFile;
} }
/** /**
* @return Returns the nF product which will keep our CityGML. * @return Returns the nF product which will keep our CityGML.
*/ */
public String getProduct() { public String getProduct() {
return product; return product;
} }
/** /**
* Sets the nF product for this import job. * Sets the nF product for this import job.
* *
* @param product The product of our import job. * @param product The product of our import job.
*/ */
public void setProduct(String product) { public void setProduct(String product) {
this.product = product; this.product = product;
} }
/** /**
* @return Returns the nF leaf of the nF product. * @return Returns the nF leaf of the nF product.
*/ */
public String getLeaf() { public String getLeaf() {
return leaf; return leaf;
} }
/** /**
* Sets the nF leaf for the nF product. * Sets the nF leaf for the nF product.
* *
* @param leaf The leaf for the nF product. * @param leaf The leaf for the nF product.
*/ */
public void setLeaf(String leaf) { public void setLeaf(String leaf) {
this.leaf = leaf; this.leaf = leaf;
} }
/** /**
* @return Returns the level of the product. * @return Returns the level of the product.
*/ */
public String getLevel() { public String getLevel() {
return level; return level;
} }
/** /**
* Sets the nF level for the nF product. * Sets the nF level for the nF product.
* *
* @param level The level for the nF product. * @param level The level for the nF product.
*/ */
public void setLevel(String level) { public void setLevel(String level) {
this.level = level; this.level = level;
} }
/** /**
* If your CityGML file encodes ADE specific elements then you have to add the corresponding schema * If your CityGML file encodes ADE specific elements then you have to add the corresponding schema
* definition file of the used ADE here. * definition file of the used ADE here.
* *
* @param adeSchemaFile The schema definition of the used ADE. * @param adeSchemaFile The schema definition of the used ADE.
*/ */
public void addADESchemaFile(File adeSchemaFile) { public void addADESchemaFile(File adeSchemaFile) {
adeSchemaFileList.add(adeSchemaFile); adeSchemaFileList.add(adeSchemaFile);
} }
/** /**
* @return Returns the list of ADE schemata which are used within your CityGML file. * @return Returns the list of ADE schemata which are used within your CityGML file.
*/ */
public ArrayList<File> getADESchemaFileList() { public ArrayList<File> getADESchemaFileList() {
return adeSchemaFileList; return adeSchemaFileList;
} }
/** /**
* @return Returns the operation which should be conducted for the features of the CityGML file. * @return Returns the operation which should be conducted for the features of the CityGML file.
*/ */
public Operation getOperation() { public Operation getOperation() {
return operation; return operation;
} }
/** /**
* Sets the operation which should be conducted for the feature objects of the CityGML file. * 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. * @param operation The operation which should be conducted for the feature object of the CityGML file.
*/ */
public void setOperation(Operation operation) { public void setOperation(Operation operation) {
this.operation = operation; this.operation = operation;
} }
/** /**
* @return Returns the supported nF job version. This enables your job builder instance to check if * @return Returns the supported nF job version. This enables your job builder instance to check if
* the job version is compatible with itself. * the job version is compatible with itself.
*/ */
@Override @Override
public String supportsJobVersion() { public String supportsJobVersion() {
return IMPORT_JOB_VERSION; return IMPORT_JOB_VERSION;
} }
/** /**
* This is just a prototype for presentation purposes. * This is just a prototype for presentation purposes.
*/ */
public static ImportJobDescription getDefaultDescriptor() { public static ImportJobDescription getDefaultDescriptor() {
ImportJobDescription descriptor = new ImportJobDescription(); ImportJobDescription descriptor = new ImportJobDescription();
descriptor.setLevel(DEFAULT_LEVEL); descriptor.setLevel(DEFAULT_LEVEL);
return descriptor; return descriptor;
} }
/** /**
* @return Returns true, if product, leaf, level and CityGML file are present. * @return Returns true, if product, leaf, level and CityGML file are present.
*/ */
public boolean isValid() { public boolean isValid() {
if (product.isEmpty() if (product.isEmpty()
|| leaf.isEmpty() || leaf.isEmpty()
|| level.isEmpty() || level.isEmpty()
|| Objects.isNull(cityGMLFile) || Objects.isNull(cityGMLFile)
|| !cityGMLFile.canRead()) { || !cityGMLFile.canRead()) {
return false; return false;
} else { } else {
return true; return true;
} }
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.io.File; import java.io.File;
import eu.simstadt.nf4j.ExportJobDescriptor; import eu.simstadt.nf4j.ExportJobDescriptor;
import eu.simstadt.nf4j.ImportJobDescriptor; import eu.simstadt.nf4j.ImportJobDescriptor;
import eu.simstadt.nf4j.InvalidJobDescriptorException; import eu.simstadt.nf4j.InvalidJobDescriptorException;
/** /**
* Implementations of JobBuilder build nF import and export jobs using nF's XML job format. There should be * Implementations of JobBuilder build nF import and export jobs using nF's XML job format. There should be
* one implementation for each version of novaFACTORY. The supported version should be returned by * one implementation for each version of novaFACTORY. The supported version should be returned by
* supportsNFVersion(). * supportsNFVersion().
* *
* @param <I> The import job descriptor implementation for this builder. * @param <I> The import job descriptor implementation for this builder.
* @param <E> The export job descriptor implementation for this builder. * @param <E> The export job descriptor implementation for this builder.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public interface JobFileBuilder<I extends ImportJobDescriptor, E extends ExportJobDescriptor> { public interface JobFileBuilder<I extends ImportJobDescriptor, E extends ExportJobDescriptor> {
/** /**
* @return Tells the caller the supported version of novaFACTORY. * @return Tells the caller the supported version of novaFACTORY.
*/ */
public String supportsNFVersion(); public String supportsNFVersion();
/** /**
* @return The supported version of the XML export job format. * @return The supported version of the XML export job format.
*/ */
public String supportsExportJobVersion(); public String supportsExportJobVersion();
/** /**
* @return The supported version of the XML import job format. * @return The supported version of the XML import job format.
*/ */
public String supportsImportJobVersion(); public String supportsImportJobVersion();
/** /**
* Builds a XML export job document. This file can be sent to a nF server instance by the caller afterwards. * Builds a XML export job document. This file can be sent to a nF server instance by the caller afterwards.
* *
* @param jobDescriptor A job descriptor which describes the export job with all its attributes according to * @param jobDescriptor A job descriptor which describes the export job with all its attributes according to
* a valid nF export job DTD. * a valid nF export job DTD.
* @return Returns a XML export job document. * @return Returns a XML export job document.
*/ */
public File buildExportJobFile(E exportJobDescriptor) throws InvalidJobDescriptorException; public File buildExportJobFile(E exportJobDescriptor) throws InvalidJobDescriptorException;
/** /**
* Builds a zipped import job file. This file can be sent to a nF server instance by the caller afterwards. * Builds a zipped import job file. This file can be sent to a nF server instance by the caller afterwards.
* *
* @param jobDescriptor A job descriptor which describes the import job with all its attributes according to * @param jobDescriptor A job descriptor which describes the import job with all its attributes according to
* the nF manual. * the nF manual.
* @return Returns a zipped import job file. * @return Returns a zipped import job file.
*/ */
public File buildImportJobFile(I importJobDescriptor) throws InvalidJobDescriptorException; public File buildImportJobFile(I importJobDescriptor) throws InvalidJobDescriptorException;
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import org.osgeo.proj4j.BasicCoordinateTransform; import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory; import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem; import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.ProjCoordinate; import org.osgeo.proj4j.ProjCoordinate;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import eu.simstadt.nf4j.InvalidJobDescriptorException; import eu.simstadt.nf4j.InvalidJobDescriptorException;
/** /**
* Builds nF import and export jobs using nF's XML job format. Please read the nF manual if you want more details about * Builds nF import and export jobs using nF's XML job format. Please read the nF manual if you want more details about
* the numerous job attributes listed below. * the numerous job attributes listed below.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class JobFileBuilderImpl implements JobFileBuilder<ImportJobDescription, ExportJobDescription> public class JobFileBuilderImpl implements JobFileBuilder<ImportJobDescription, ExportJobDescription>
{ {
/** Supported version of the novaFACTORY. */ /** Supported version of the novaFACTORY. */
public static final String NOVA_FACTORY_VERSION = "6.3.1.1"; public static final String NOVA_FACTORY_VERSION = "6.3.1.1";
/** The version of the XML export job format. */ /** The version of the XML export job format. */
public static final String EXPORT_JOB_VERSION = "1.0.0"; public static final String EXPORT_JOB_VERSION = "1.0.0";
/** /**
* @return Returns the supported novaFACTORY version. * @return Returns the supported novaFACTORY version.
*/ */
@Override @Override
public String supportsNFVersion() { public String supportsNFVersion() {
return NOVA_FACTORY_VERSION; return NOVA_FACTORY_VERSION;
} }
/** /**
* @return Returns the supported XML export job version. * @return Returns the supported XML export job version.
*/ */
@Override @Override
public String supportsExportJobVersion() { public String supportsExportJobVersion() {
return EXPORT_JOB_VERSION; return EXPORT_JOB_VERSION;
} }
/** /**
* @return Returns the supported XML import job version. * @return Returns the supported XML import job version.
*/ */
@Override @Override
public String supportsImportJobVersion() { public String supportsImportJobVersion() {
return null; return null;
} }
/** /**
* This is an intermediate prototype. * This is an intermediate prototype.
* *
* @param jobDescriptor A job descriptor which describes the export job with all its attributes according to a valid * @param jobDescriptor A job descriptor which describes the export job with all its attributes according to a valid
* nF export job DTD. * nF export job DTD.
* @return Returns a string representation of the nF export job. * @return Returns a string representation of the nF export job.
* @throws FailedJobTransmissionException * @throws FailedJobTransmissionException
*/ */
@Override @Override
public File buildExportJobFile(ExportJobDescription jobDescriptor) throws InvalidJobDescriptorException { public File buildExportJobFile(ExportJobDescription jobDescriptor) throws InvalidJobDescriptorException {
File result = null; File result = null;
if (Objects.nonNull(jobDescriptor) && jobDescriptor.isValid()) { if (Objects.nonNull(jobDescriptor) && jobDescriptor.isValid()) {
try { try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument(); Document doc = builder.newDocument();
Element root = doc.createElement("EXPORT_JOB"); Element root = doc.createElement("EXPORT_JOB");
root.setAttribute("version", supportsExportJobVersion()); root.setAttribute("version", supportsExportJobVersion());
doc.appendChild(root); doc.appendChild(root);
Element job = doc.createElement("job"); Element job = doc.createElement("job");
root.appendChild(job); root.appendChild(job);
Element initiator = doc.createElement("initiator"); Element initiator = doc.createElement("initiator");
initiator.appendChild(doc.createTextNode(jobDescriptor.getInitiator())); initiator.appendChild(doc.createTextNode(jobDescriptor.getInitiator()));
job.appendChild(initiator); job.appendChild(initiator);
Element jobnumber = doc.createElement("jobnumber"); Element jobnumber = doc.createElement("jobnumber");
jobnumber.appendChild(doc.createTextNode(jobDescriptor.getJobnumber())); jobnumber.appendChild(doc.createTextNode(jobDescriptor.getJobnumber()));
job.appendChild(jobnumber); job.appendChild(jobnumber);
Element account = doc.createElement("account"); Element account = doc.createElement("account");
account.appendChild(doc.createTextNode(System.getProperty("user.name"))); account.appendChild(doc.createTextNode(System.getProperty("user.name")));
job.appendChild(account); job.appendChild(account);
Element product = doc.createElement("product"); Element product = doc.createElement("product");
product.appendChild(doc.createTextNode(jobDescriptor.getProduct())); product.appendChild(doc.createTextNode(jobDescriptor.getProduct()));
root.appendChild(product); root.appendChild(product);
Element layers = doc.createElement("layers"); Element layers = doc.createElement("layers");
layers.setAttribute("color", jobDescriptor.getColor()); layers.setAttribute("color", jobDescriptor.getColor());
layers.setAttribute("mono", jobDescriptor.getMono()); layers.setAttribute("mono", jobDescriptor.getMono());
layers.setAttribute("plotLabelSrs", jobDescriptor.getPlotLabelSrs()); layers.setAttribute("plotLabelSrs", jobDescriptor.getPlotLabelSrs());
layers.setAttribute("plotframe", jobDescriptor.getPlotframe()); layers.setAttribute("plotframe", jobDescriptor.getPlotframe());
layers.setAttribute("single", jobDescriptor.getSingle()); layers.setAttribute("single", jobDescriptor.getSingle());
root.appendChild(layers); root.appendChild(layers);
appendLayers(doc, layers, jobDescriptor.getLayerList()); appendLayers(doc, layers, jobDescriptor.getLayerList());
Element srs = doc.createElement("srs"); Element srs = doc.createElement("srs");
srs.appendChild(doc.createTextNode(jobDescriptor.getSrs())); srs.appendChild(doc.createTextNode(jobDescriptor.getSrs()));
root.appendChild(srs); root.appendChild(srs);
Element extent = doc.createElement("extent"); Element extent = doc.createElement("extent");
extent.setAttribute("merge_mapsheets", jobDescriptor.getMergeMapsheets()); extent.setAttribute("merge_mapsheets", jobDescriptor.getMergeMapsheets());
root.appendChild(extent); root.appendChild(extent);
if (!jobDescriptor.getUnitList().isEmpty()) { if (!jobDescriptor.getUnitList().isEmpty()) {
extent.setAttribute("tile1asgn", jobDescriptor.getTile1asgn()); extent.setAttribute("tile1asgn", jobDescriptor.getTile1asgn());
for (Unit unit : jobDescriptor.getUnitList()) { for (Unit unit : jobDescriptor.getUnitList()) {
Element unitElement = doc.createElement("unit"); Element unitElement = doc.createElement("unit");
unitElement.setAttribute("exterior", unit.getExterior()); unitElement.setAttribute("exterior", unit.getExterior());
unitElement.setAttribute("frame", unit.getFrame()); unitElement.setAttribute("frame", unit.getFrame());
unitElement.setAttribute("select_mapsheets", unit.getSelectMapsheets()); unitElement.setAttribute("select_mapsheets", unit.getSelectMapsheets());
unitElement.setAttribute("subdivision", unit.getSubdivision()); unitElement.setAttribute("subdivision", unit.getSubdivision());
unitElement.appendChild(doc.createTextNode(unit.getValue())); unitElement.appendChild(doc.createTextNode(unit.getValue()));
extent.appendChild(unitElement); extent.appendChild(unitElement);
} }
} else { } else {
Element polygon = createRegionPolygonElement(doc, jobDescriptor.regionPolygon); Element polygon = createRegionPolygonElement(doc, jobDescriptor.regionPolygon);
extent.appendChild(polygon); extent.appendChild(polygon);
} }
Element resolution = doc.createElement("resolution"); Element resolution = doc.createElement("resolution");
resolution.appendChild(doc.createTextNode(jobDescriptor.getResolution())); resolution.appendChild(doc.createTextNode(jobDescriptor.getResolution()));
root.appendChild(resolution); root.appendChild(resolution);
Element scale = doc.createElement("scale"); Element scale = doc.createElement("scale");
scale.appendChild(doc.createTextNode(jobDescriptor.getScale())); scale.appendChild(doc.createTextNode(jobDescriptor.getScale()));
root.appendChild(scale); root.appendChild(scale);
Element format = doc.createElement("format"); Element format = doc.createElement("format");
format.setAttribute("alphalinscale", "0.0"); format.setAttribute("alphalinscale", "0.0");
format.setAttribute("alphascale", "1.0"); format.setAttribute("alphascale", "1.0");
format.setAttribute("citygml_actfunc", "undef"); format.setAttribute("citygml_actfunc", "undef");
format.setAttribute("citygml_apptheme", ""); format.setAttribute("citygml_apptheme", "");
format.setAttribute("citygml_elemclasses", "true"); format.setAttribute("citygml_elemclasses", "true");
format.setAttribute("citygml_lodmode", "all"); format.setAttribute("citygml_lodmode", "all");
format.setAttribute("citygml_lods", jobDescriptor.getLODs()); format.setAttribute("citygml_lods", jobDescriptor.getLODs());
format.setAttribute("citygml_metadata", "true"); format.setAttribute("citygml_metadata", "true");
format.setAttribute("citygml_outmode", "normal"); format.setAttribute("citygml_outmode", "normal");
format.setAttribute("dtm", "false"); format.setAttribute("dtm", "false");
format.setAttribute("foredit", "false"); format.setAttribute("foredit", "false");
format.setAttribute("materialcopymode", "none"); format.setAttribute("materialcopymode", "none");
format.setAttribute("polyopts_reverse", "false"); format.setAttribute("polyopts_reverse", "false");
format.setAttribute("relcoords", "false"); format.setAttribute("relcoords", "false");
format.setAttribute("rooftxr", "false"); format.setAttribute("rooftxr", "false");
format.setAttribute("roundcoords", "3"); format.setAttribute("roundcoords", "3");
format.setAttribute("schemetxr", "false"); format.setAttribute("schemetxr", "false");
format.setAttribute("solar", "false"); format.setAttribute("solar", "false");
format.setAttribute("solargeoplex", "false"); format.setAttribute("solargeoplex", "false");
format.setAttribute("tex", "false"); format.setAttribute("tex", "false");
format.setAttribute("tolod1", "false"); format.setAttribute("tolod1", "false");
format.setAttribute("xyz", "false"); format.setAttribute("xyz", "false");
format.appendChild(doc.createTextNode("CityGML")); format.appendChild(doc.createTextNode("CityGML"));
root.appendChild(format); root.appendChild(format);
Element exportmetadata = doc.createElement("exportmetadata"); Element exportmetadata = doc.createElement("exportmetadata");
exportmetadata.setAttribute("calibration", jobDescriptor.getCalibration()); exportmetadata.setAttribute("calibration", jobDescriptor.getCalibration());
exportmetadata.setAttribute("xmetadata", jobDescriptor.getXmetadata()); exportmetadata.setAttribute("xmetadata", jobDescriptor.getXmetadata());
exportmetadata.appendChild(doc.createTextNode(jobDescriptor.getExportmetadata())); exportmetadata.appendChild(doc.createTextNode(jobDescriptor.getExportmetadata()));
root.appendChild(exportmetadata); root.appendChild(exportmetadata);
Element addfile = doc.createElement("addfile"); Element addfile = doc.createElement("addfile");
addfile.setAttribute("col", jobDescriptor.getCol()); addfile.setAttribute("col", jobDescriptor.getCol());
addfile.setAttribute("eck", jobDescriptor.getEck()); addfile.setAttribute("eck", jobDescriptor.getEck());
root.appendChild(addfile); root.appendChild(addfile);
Element usenodatamask = doc.createElement("usenodatamask"); Element usenodatamask = doc.createElement("usenodatamask");
usenodatamask.appendChild(doc.createTextNode(jobDescriptor.getUsenodatamask())); usenodatamask.appendChild(doc.createTextNode(jobDescriptor.getUsenodatamask()));
root.appendChild(usenodatamask); root.appendChild(usenodatamask);
Element usepdctborderpoly = doc.createElement("usepdctborderpoly"); Element usepdctborderpoly = doc.createElement("usepdctborderpoly");
usepdctborderpoly.appendChild(doc.createTextNode(jobDescriptor.getUsepdctborderpoly())); usepdctborderpoly.appendChild(doc.createTextNode(jobDescriptor.getUsepdctborderpoly()));
root.appendChild(usepdctborderpoly); root.appendChild(usepdctborderpoly);
Element dhkresolvereferences = doc.createElement("dhkresolvereferences"); Element dhkresolvereferences = doc.createElement("dhkresolvereferences");
dhkresolvereferences.appendChild(doc.createTextNode(jobDescriptor.getDhkresolvereferences())); dhkresolvereferences.appendChild(doc.createTextNode(jobDescriptor.getDhkresolvereferences()));
root.appendChild(dhkresolvereferences); root.appendChild(dhkresolvereferences);
Element zipresult = doc.createElement("zipresult"); Element zipresult = doc.createElement("zipresult");
zipresult.appendChild(doc.createTextNode(jobDescriptor.getZipresult())); zipresult.appendChild(doc.createTextNode(jobDescriptor.getZipresult()));
root.appendChild(zipresult); root.appendChild(zipresult);
Element userdescription = doc.createElement("userdescription"); Element userdescription = doc.createElement("userdescription");
root.appendChild(userdescription); root.appendChild(userdescription);
Element namingpattern = doc.createElement("namingpattern"); Element namingpattern = doc.createElement("namingpattern");
root.appendChild(namingpattern); root.appendChild(namingpattern);
TransformerFactory transformerFactory = TransformerFactory.newInstance(); TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(); Transformer transformer = transformerFactory.newTransformer();
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
StreamResult streamResult = new StreamResult(writer); StreamResult streamResult = new StreamResult(writer);
transformer.transform(new DOMSource(doc), streamResult); transformer.transform(new DOMSource(doc), streamResult);
File tempfile = File.createTempFile(jobDescriptor.getProduct() + "_", ".xml"); File tempfile = File.createTempFile(jobDescriptor.getProduct() + "_", ".xml");
PrintWriter printWriter = new PrintWriter(tempfile); PrintWriter printWriter = new PrintWriter(tempfile);
printWriter.print(writer.toString()); printWriter.print(writer.toString());
printWriter.close(); printWriter.close();
return tempfile; return tempfile;
} catch (ParserConfigurationException ex) { } catch (ParserConfigurationException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} catch (TransformerConfigurationException ex) { } catch (TransformerConfigurationException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} catch (TransformerException ex) { } catch (TransformerException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} catch (IOException ex) { } catch (IOException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} }
} else { } else {
throw new InvalidJobDescriptorException(); throw new InvalidJobDescriptorException();
} }
return result; return result;
} }
/** /**
* Appends layers to the XML job document. * Appends layers to the XML job document.
* *
* @param doc The XML document. * @param doc The XML document.
* @param layers The XML layers element where new layers should be appended. * @param layers The XML layers element where new layers should be appended.
* @param layerList The user defined list of layers. * @param layerList The user defined list of layers.
*/ */
private void appendLayers(Document doc, Element layers, private void appendLayers(Document doc, Element layers,
ArrayList<Layer> layerList) { ArrayList<Layer> layerList) {
for (Layer layer : layerList) { for (Layer layer : layerList) {
Element layerElement = doc.createElement("layer"); Element layerElement = doc.createElement("layer");
layerElement.setAttribute("name", layer.getName()); layerElement.setAttribute("name", layer.getName());
String product = layer.getProduct(); String product = layer.getProduct();
if (Objects.nonNull(product) && !product.isEmpty()) { if (Objects.nonNull(product) && !product.isEmpty()) {
layerElement.setAttribute("product", product); layerElement.setAttribute("product", product);
} }
String style = layer.getStyle(); String style = layer.getStyle();
if (Objects.nonNull(style) && !style.isEmpty()) { if (Objects.nonNull(style) && !style.isEmpty()) {
layerElement.setAttribute("style", style); layerElement.setAttribute("style", style);
} }
layers.appendChild(layerElement); layers.appendChild(layerElement);
} }
} }
/** /**
* Transforms a global WGS 84 position into a coordinate of the given target SRS. * Transforms a global WGS 84 position into a coordinate of the given target SRS.
* *
* @param wgs84Position The WGS 84 position to be transformed to a position within the target SRS. * @param wgs84Position The WGS 84 position to be transformed to a position within the target SRS.
* @param targetCRS The target SRS for the transformation. * @param targetCRS The target SRS for the transformation.
* @return The transformed target position within the target SRS. * @return The transformed target position within the target SRS.
*/ */
public static ProjCoordinate transformCoordinate(ProjCoordinate wgs84Position, public static ProjCoordinate transformCoordinate(ProjCoordinate wgs84Position,
CoordinateReferenceSystem targetCRS) { CoordinateReferenceSystem targetCRS) {
ProjCoordinate result = new ProjCoordinate(); ProjCoordinate result = new ProjCoordinate();
CRSFactory f = new CRSFactory(); CRSFactory f = new CRSFactory();
CoordinateReferenceSystem sourceCRS = f.createFromName(CRSWKT.EPSG_4326.wkt); // WGS 84 (used by Google Maps / OpenStreetMap) CoordinateReferenceSystem sourceCRS = f.createFromName(CRSWKT.EPSG_4326.wkt); // WGS 84 (used by Google Maps / OpenStreetMap)
BasicCoordinateTransform transform = new BasicCoordinateTransform(sourceCRS, targetCRS); BasicCoordinateTransform transform = new BasicCoordinateTransform(sourceCRS, targetCRS);
transform.transform(wgs84Position, result); transform.transform(wgs84Position, result);
return result; return result;
} }
/** /**
* Appends the region polygon to the XML export job document. In order to do this, the given WGS 84 region polygon * Appends the region polygon to the XML export job document. In order to do this, the given WGS 84 region polygon
* will be transformed into a DHDN Gauss-Kruger zone 3 polygon. * will be transformed into a DHDN Gauss-Kruger zone 3 polygon.
* *
* @param doc The XML export job document. * @param doc The XML export job document.
* @param regionPolygon The polygon of the region which has been selected to be exported. * @param regionPolygon The polygon of the region which has been selected to be exported.
* @return The w3c.dom.Element of the XML export job which describes the region polygon. * @return The w3c.dom.Element of the XML export job which describes the region polygon.
*/ */
private static Element createRegionPolygonElement(Document doc, List<Coord> regionPolygon) { private static Element createRegionPolygonElement(Document doc, List<Coord> regionPolygon) {
Element polygon = doc.createElement("polygon"); Element polygon = doc.createElement("polygon");
polygon.setAttribute("srs", "31467"); polygon.setAttribute("srs", "31467");
CRSFactory f = new CRSFactory(); CRSFactory f = new CRSFactory();
CoordinateReferenceSystem targetCRS = f.createFromName(CRSWKT.EPSG_31467.wkt); // DHDN Gauss-Kruger zone 3 CoordinateReferenceSystem targetCRS = f.createFromName(CRSWKT.EPSG_31467.wkt); // DHDN Gauss-Kruger zone 3
for (Coord coord : regionPolygon) { for (Coord coord : regionPolygon) {
ProjCoordinate sourcePosition = new ProjCoordinate(coord.longitude, coord.latitude); ProjCoordinate sourcePosition = new ProjCoordinate(coord.longitude, coord.latitude);
ProjCoordinate targetPosition = transformCoordinate(sourcePosition, targetCRS); ProjCoordinate targetPosition = transformCoordinate(sourcePosition, targetCRS);
Element vertex = doc.createElement("vertex"); Element vertex = doc.createElement("vertex");
vertex.setAttribute("x", String.valueOf(targetPosition.x)); vertex.setAttribute("x", String.valueOf(targetPosition.x));
vertex.setAttribute("y", String.valueOf(targetPosition.y)); vertex.setAttribute("y", String.valueOf(targetPosition.y));
polygon.appendChild(vertex); polygon.appendChild(vertex);
} }
return polygon; return polygon;
} }
/** /**
* Builds a zipped import job file. This file can be sent to a nF server instance by the caller afterwards. * Builds a zipped import job file. This file can be sent to a nF server instance by the caller afterwards.
* *
* @param jobDescriptor A job descriptor which describes the import job with all its attributes according to a valid * @param jobDescriptor A job descriptor which describes the import job with all its attributes according to a valid
* nF import job DTD. * nF import job DTD.
* @return Returns a XML import job document. * @return Returns a XML import job document.
*/ */
@Override @Override
public File buildImportJobFile(ImportJobDescription jobDescriptor) public File buildImportJobFile(ImportJobDescription jobDescriptor)
throws InvalidJobDescriptorException { throws InvalidJobDescriptorException {
if (Objects.nonNull(jobDescriptor) && jobDescriptor.isValid()) { if (Objects.nonNull(jobDescriptor) && jobDescriptor.isValid()) {
try { try {
// Write the nF start file which triggers and controls the processing of the CityGML file. // Write the nF start file which triggers and controls the processing of the CityGML file.
String startFilename = jobDescriptor.getProduct() + "_" + jobDescriptor.getLeaf() + ".start"; String startFilename = jobDescriptor.getProduct() + "_" + jobDescriptor.getLeaf() + ".start";
File startfile = new File(System.getProperty("java.io.tmpdir"), startFilename); File startfile = new File(System.getProperty("java.io.tmpdir"), startFilename);
PrintWriter writer = new PrintWriter(startfile); PrintWriter writer = new PrintWriter(startfile);
writer.print(jobDescriptor.getLevel()); writer.print(jobDescriptor.getLevel());
writer.close(); writer.close();
// Zip start file, CityGML file and ADE schemata // Zip start file, CityGML file and ADE schemata
File zippedCityGMLFile = File.createTempFile("nF_Import_", ".zip"); File zippedCityGMLFile = File.createTempFile("nF_Import_", ".zip");
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zippedCityGMLFile)); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zippedCityGMLFile));
String zipFileName = jobDescriptor.getProduct() + "_" + jobDescriptor.getLeaf() + "_" String zipFileName = jobDescriptor.getProduct() + "_" + jobDescriptor.getLeaf() + "_"
+ jobDescriptor.getLevel(); + jobDescriptor.getLevel();
if (Objects.nonNull(jobDescriptor.getOperation())) { if (Objects.nonNull(jobDescriptor.getOperation())) {
zipFileName += "_" + jobDescriptor.getOperation(); zipFileName += "_" + jobDescriptor.getOperation();
} }
zipFileName += ".gml"; zipFileName += ".gml";
File cityGMLFile = jobDescriptor.getCityGMLFile(); File cityGMLFile = jobDescriptor.getCityGMLFile();
writeBytesToZipFile(new FileInputStream(cityGMLFile), zos, zipFileName); writeBytesToZipFile(new FileInputStream(cityGMLFile), zos, zipFileName);
writeBytesToZipFile(new FileInputStream(startfile), zos, startFilename); writeBytesToZipFile(new FileInputStream(startfile), zos, startFilename);
for (File adeSchemaFile : jobDescriptor.getADESchemaFileList()) { for (File adeSchemaFile : jobDescriptor.getADESchemaFileList()) {
writeBytesToZipFile(new FileInputStream(adeSchemaFile), zos, adeSchemaFile.getName()); writeBytesToZipFile(new FileInputStream(adeSchemaFile), zos, adeSchemaFile.getName());
} }
zos.close(); zos.close();
return zippedCityGMLFile; return zippedCityGMLFile;
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} catch (IOException ex) { } catch (IOException ex) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
ex.printStackTrace(); ex.printStackTrace();
} }
} else { } else {
throw new InvalidJobDescriptorException(); throw new InvalidJobDescriptorException();
} }
return null; return null;
} }
/** /**
* Writes a file to the given ZipOutputStream which compresses the file. * Writes a file to the given ZipOutputStream which compresses the file.
* *
* @param fis The file input stream to be compressed. * @param fis The file input stream to be compressed.
* @param zos The zip output stream. * @param zos The zip output stream.
* @param zipEntry The new zip entry for the file to be compressed. * @param zipEntry The new zip entry for the file to be compressed.
* @throws IOException You will get some of this, if your streams point to nirvana. * @throws IOException You will get some of this, if your streams point to nirvana.
*/ */
private void writeBytesToZipFile(FileInputStream fis, ZipOutputStream zos, String zipEntry) private void writeBytesToZipFile(FileInputStream fis, ZipOutputStream zos, String zipEntry)
throws IOException { throws IOException {
zos.putNextEntry(new ZipEntry(zipEntry)); zos.putNextEntry(new ZipEntry(zipEntry));
byte[] b = new byte[1024]; byte[] b = new byte[1024];
int chunkSize; int chunkSize;
while ((chunkSize = fis.read(b)) > 0) { while ((chunkSize = fis.read(b)) > 0) {
zos.write(b, 0, chunkSize); zos.write(b, 0, chunkSize);
} }
fis.close(); fis.close();
} }
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.util.EventObject; import java.util.EventObject;
import java.util.Optional; import java.util.Optional;
import eu.simstadt.nf4j.Job; import eu.simstadt.nf4j.Job;
import eu.simstadt.nf4j.JobStatus; import eu.simstadt.nf4j.JobStatus;
/** /**
* Every time when the status of a job progresses, one of this events will be created and sent * Every time when the status of a job progresses, one of this events will be created and sent
* to all of the job status listeners registered at the job. Job status listeners implement * to all of the job status listeners registered at the job. Job status listeners implement
* the jobStatusChanged() method which takes this JobStatusEvent as its argument. This event will * the jobStatusChanged() method which takes this JobStatusEvent as its argument. This event will
* contain the job status as the event source and listener can read the source and decide how to * contain the job status as the event source and listener can read the source and decide how to
* deal with the new status of its observed job. * deal with the new status of its observed job.
* *
* Note, the job status, job and additional event messages will be referenced in extra object members of this event, * Note, the job status, job and additional event messages will be referenced in extra object members of this event,
* because the status of referenced job may change during the notification of the listeners. Therefore, obtaining * because the status of referenced job may change during the notification of the listeners. Therefore, obtaining
* the job status directly from the job is not reliable, if the listener wants to know the actual source of this * the job status directly from the job is not reliable, if the listener wants to know the actual source of this
* event. * event.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class JobStatusEvent extends EventObject { public class JobStatusEvent extends EventObject {
private static final long serialVersionUID = -1800246486543538087L; private static final long serialVersionUID = -1800246486543538087L;
/** The job for which this event will be sent to the job status listeners. */ /** The job for which this event will be sent to the job status listeners. */
private Job job; private Job job;
/** There might be an additional (error) message provided with the new job status. */ /** There might be an additional (error) message provided with the new job status. */
private Optional<String> message; private Optional<String> message;
/** /**
* Constructor with job status as event source. The source can be read by the job status listeners. * Constructor with job status as event source. The source can be read by the job status listeners.
* *
* @param source The new job status, which triggers this event. * @param source The new job status, which triggers this event.
*/ */
public JobStatusEvent(JobStatus source, Job job) { public JobStatusEvent(JobStatus source, Job job) {
this(source, job, null); this(source, job, null);
} }
/** /**
* Constructor with job status as event source and an additional (error) message. The source can be read * Constructor with job status as event source and an additional (error) message. The source can be read
* by the job status listeners. * by the job status listeners.
* *
* @param source The new job status, which triggers this event. * @param source The new job status, which triggers this event.
* @param message an additional (error) message for this event and job status. * @param message an additional (error) message for this event and job status.
*/ */
public JobStatusEvent(JobStatus source, Job job, Optional<String> message) { public JobStatusEvent(JobStatus source, Job job, Optional<String> message) {
super(source); super(source);
this.job = job; this.job = job;
this.message = message; this.message = message;
} }
/** /**
* @return Returns the job for which this event will be sent to the job status listeners. * @return Returns the job for which this event will be sent to the job status listeners.
*/ */
public Job getJob() { public Job getJob() {
return job; return job;
} }
/** /**
* @return Returns an additional (error) message, if present. * @return Returns an additional (error) message, if present.
*/ */
public Optional<String> getMessage() { public Optional<String> getMessage() {
return message; return message;
} }
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.util.EventListener; import java.util.EventListener;
/** /**
* Your main application may become a job status listener in order to get updates about the status changes of its * Your main application may become a job status listener in order to get updates about the status changes of its
* ongoing jobs. Job listeners of asynchronous export and import jobs will receive event objects for most of the * ongoing jobs. Job listeners of asynchronous export and import jobs will receive event objects for most of the
* job status' listed in the job status enumeration. * job status' listed in the job status enumeration.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public interface JobStatusListener extends EventListener { public interface JobStatusListener extends EventListener {
/** /**
* This callback method will be called by your asynchronous export and import jobs during their send, poll * This callback method will be called by your asynchronous export and import jobs during their send, poll
* and download operations in order to keep you updated about job status changes. * and download operations in order to keep you updated about job status changes.
* *
* @param event The latest job status event for one of your export or import jobs. * @param event The latest job status event for one of your export or import jobs.
*/ */
public void jobStatusChanged(JobStatusEvent event); public void jobStatusChanged(JobStatusEvent event);
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
/** /**
* A layer describes an aspect of a nF product and the type of its data. For instance, a layer could contain * A layer describes an aspect of a nF product and the type of its data. For instance, a layer could contain
* all house numbers of all buildings of the product. * all house numbers of all buildings of the product.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class Layer { public class Layer {
private static final String DEFAULT_NAME = "GML"; private static final String DEFAULT_NAME = "GML";
private static final String DEFAULT_PRODUCT = "WU3"; private static final String DEFAULT_PRODUCT = "WU3";
private static final String DEFAULT_STYLE = "#000000"; private static final String DEFAULT_STYLE = "#000000";
/** The name of the layer. */ /** The name of the layer. */
private String name; private String name;
/** The name of the product to which this layer belongs. */ /** The name of the product to which this layer belongs. */
private String product; private String product;
/** The style of this layer. Should be a color code (?). */ /** The style of this layer. Should be a color code (?). */
private String style; private String style;
/** /**
* The standard constructor. * The standard constructor.
*/ */
public Layer() {} public Layer() {}
/** /**
* A convenience constructor for layers. * A convenience constructor for layers.
* *
* @param name The name of the layer. This layer has to exist within the product. * @param name The name of the layer. This layer has to exist within the product.
* @param product The name of the product. This product has to exist in the database. * @param product The name of the product. This product has to exist in the database.
* @param style The purpose of this field is unknown. * @param style The purpose of this field is unknown.
*/ */
public Layer(String name, String product, String style) { public Layer(String name, String product, String style) {
this.name = name; this.name = name;
this.product = product; this.product = product;
this.style = style; this.style = style;
} }
/** /**
* @return Returns the name of the layer. * @return Returns the name of the layer.
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* Sets the name of the layer. * Sets the name of the layer.
* *
* @param name The name of the layer. * @param name The name of the layer.
*/ */
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/** /**
* @return Returns the name of the layer's product. * @return Returns the name of the layer's product.
*/ */
public String getProduct() { public String getProduct() {
return product; return product;
} }
/** /**
* Sets the product of this layer. * Sets the product of this layer.
* *
* @param product The product of this layer. * @param product The product of this layer.
*/ */
public void setProduct(String product) { public void setProduct(String product) {
this.product = product; this.product = product;
} }
/** /**
* @return Returns the style of the layer. * @return Returns the style of the layer.
*/ */
public String getStyle() { public String getStyle() {
return style; return style;
} }
/** /**
* Sets the style of this layer. Should be a color code (?). * Sets the style of this layer. Should be a color code (?).
* *
* @param style The style of this layer. * @param style The style of this layer.
*/ */
public void setStyle(String style) { public void setStyle(String style) {
this.style = style; this.style = style;
} }
public static Layer getDefaultLayer() { public static Layer getDefaultLayer() {
Layer layer = new Layer(); Layer layer = new Layer();
layer.setName(DEFAULT_NAME); layer.setName(DEFAULT_NAME);
layer.setProduct(DEFAULT_PRODUCT); layer.setProduct(DEFAULT_PRODUCT);
layer.setStyle(DEFAULT_STYLE); layer.setStyle(DEFAULT_STYLE);
return layer; return layer;
} }
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
/** /**
* These are the known operation modes of the nF import servlet. * These are the known operation modes of the nF import servlet.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public enum Operation { public enum Operation {
REP, // Replaces whole existing buildings, REP, // Replaces whole existing buildings,
REPUPD, // Replaces whole existing buildings and adds new buildings, REPUPD, // Replaces whole existing buildings and adds new buildings,
UPD, // Update, same as REP, UPD, // Update, same as REP,
CHG, // Change, same as REPUPD, CHG, // Change, same as REPUPD,
DEL, // Deletes the geometry of a particular LOD, DEL, // Deletes the geometry of a particular LOD,
DELALL // Deletes a whole building DELALL // Deletes a whole building
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import eu.simstadt.nf4j.FailedTransmissionException; import eu.simstadt.nf4j.FailedTransmissionException;
/** /**
* This task frequently polls the status of an asynchronous job within a separate poll thread. Changes of the * This task frequently polls the status of an asynchronous job within a separate poll thread. Changes of the
* jobs status will be signaled to all of the job status listeners registered at the job. * jobs status will be signaled to all of the job status listeners registered at the job.
* You can cancel this task by calling job.cancel(). * You can cancel this task by calling job.cancel().
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class PollJobStatusTask implements Runnable { public class PollJobStatusTask implements Runnable {
/** The job for which you want to poll status changes for. */ /** The job for which you want to poll status changes for. */
private AsyncJob job; private AsyncJob job;
/** /**
* Don't flood your nF server with status request. This interval ensures that your server will receive * Don't flood your nF server with status request. This interval ensures that your server will receive
* a status request within every time interval. * a status request within every time interval.
*/ */
private int interval; private int interval;
/** /**
* Constructor with asynchronous job and the poll interval. * Constructor with asynchronous job and the poll interval.
* *
* @param job The job to update frequently. * @param job The job to update frequently.
* @param interval The time interval for one request. * @param interval The time interval for one request.
*/ */
public PollJobStatusTask(AsyncJob job, int interval) { public PollJobStatusTask(AsyncJob job, int interval) {
this.job = job; this.job = job;
this.interval = interval; this.interval = interval;
} }
/** /**
* This method performs the poll operation asynchronously in the jobs separate poll thread. * This method performs the poll operation asynchronously in the jobs separate poll thread.
* Job status listeners will be notified upon status changes. * Job status listeners will be notified upon status changes.
*/ */
@Override @Override
public void run() { public void run() {
try { try {
while (!job.hasFinished() && !job.hasFailed() && job.keepPolling()) { while (!job.hasFinished() && !job.hasFailed() && job.keepPolling()) {
job.triggerStatusUpdate(); job.triggerStatusUpdate();
Thread.sleep(interval * 1000l); Thread.sleep(interval * 1000l);
} }
// At this line the job may have finished or failed before the job listeners could be notified. // At this line the job may have finished or failed before the job listeners could be notified.
// Therefore, we have to ensure that all listeners know the current status. // Therefore, we have to ensure that all listeners know the current status.
job.notifyJobStatusListeners(); job.notifyJobStatusListeners();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
job.cancel(); job.cancel();
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
// Canceled by the main thread // Canceled by the main thread
} }
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
/** /**
* This SAX handler scans nF XML status reports and exception reports and searches for the nF job id, the status of a * This SAX handler scans nF XML status reports and exception reports and searches for the nF job id, the status of a
* nF job and service exception messages. * nF job and service exception messages.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class ReportHandler extends DefaultHandler { public class ReportHandler extends DefaultHandler {
/** The XML tag which tells you the status of a nF export job. */ /** The XML tag which tells you the status of a nF export job. */
public static final String STATUS_TAG = "status"; public static final String STATUS_TAG = "status";
/** The XML tag which tells you the status of a nF import job. */ /** The XML tag which tells you the status of a nF import job. */
public static final String RESULT_STATUS_TAG = "ResultStatus"; public static final String RESULT_STATUS_TAG = "ResultStatus";
/** The XML attribute which tells you the status of a nF import job. */ /** The XML attribute which tells you the status of a nF import job. */
public static final String STATUS_ATTRIBUTE = "status"; public static final String STATUS_ATTRIBUTE = "status";
/** The XML tag which holds the id of the nF job. */ /** The XML tag which holds the id of the nF job. */
public static final String JOB_ID = "jobId"; public static final String JOB_ID = "jobId";
/** If there was a problem on the nF server, then this XML tag gives you some hints. */ /** If there was a problem on the nF server, then this XML tag gives you some hints. */
public static final String SERVICE_EXCEPTION_TAG = "ServiceException"; public static final String SERVICE_EXCEPTION_TAG = "ServiceException";
/** The id of the status of the nF job. */ /** The id of the status of the nF job. */
public Integer statusId = null; public Integer statusId = null;
/** The id of the nF job. */ /** The id of the nF job. */
public Integer jobId = null; public Integer jobId = null;
/** If there was any problem, then you will find an exception message here. */ /** If there was any problem, then you will find an exception message here. */
public String serviceException = null; public String serviceException = null;
/** Scanned string will be stored here temporarily. */ /** Scanned string will be stored here temporarily. */
private String currentString; private String currentString;
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { throws SAXException {
if (qName.equalsIgnoreCase(RESULT_STATUS_TAG)) { if (qName.equalsIgnoreCase(RESULT_STATUS_TAG)) {
statusId = Integer.valueOf(attributes.getValue(STATUS_ATTRIBUTE)); statusId = Integer.valueOf(attributes.getValue(STATUS_ATTRIBUTE));
} }
} }
/** /**
* If a tag has been read, its contents will be tested here. If it contains either a status id, job id or * If a tag has been read, its contents will be tested here. If it contains either a status id, job id or
* service exception message, then the contents will be stored in the appropriate member variable. * service exception message, then the contents will be stored in the appropriate member variable.
*/ */
@Override @Override
public void endElement(String uri, String localName, String qName) throws SAXException { public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase(STATUS_TAG)) { if (qName.equalsIgnoreCase(STATUS_TAG)) {
statusId = Integer.valueOf(currentString); statusId = Integer.valueOf(currentString);
} else if (qName.equalsIgnoreCase(SERVICE_EXCEPTION_TAG)) { } else if (qName.equalsIgnoreCase(SERVICE_EXCEPTION_TAG)) {
serviceException = currentString; serviceException = currentString;
} else if (qName.equalsIgnoreCase(JOB_ID)) { } else if (qName.equalsIgnoreCase(JOB_ID)) {
jobId = Integer.valueOf(currentString); jobId = Integer.valueOf(currentString);
} }
} }
/** /**
* The scanner of the XML document. * The scanner of the XML document.
* *
* @see DefaultHandler * @see DefaultHandler
*/ */
@Override @Override
public void characters(char[] ch, int start, int length) { public void characters(char[] ch, int start, int length) {
currentString = new String(ch, start, length); currentString = new String(ch, start, length);
} }
} }
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.util.Optional; import java.util.Optional;
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;
/** /**
* This task sends an export job to your nF server asynchronously within a separate send thread. Once the send * This task sends an export job to your nF server asynchronously within a separate send thread. Once the send
* operation has finished all of the jobs status listeners will be notified. You can cancel this task by calling * operation has finished all of the jobs status listeners will be notified. You can cancel this task by calling
* job.cancel(). * job.cancel().
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class SendExportJobTask implements Runnable { public class SendExportJobTask implements Runnable {
/** The job to be sent to your nF server. */ /** The job to be sent to your nF server. */
private AsyncExportJob job; private AsyncExportJob job;
/** /**
* Constructor with the export job to be sent. * Constructor with the export job to be sent.
* *
* @param job The export job to be sent. * @param job The export job to be sent.
*/ */
public SendExportJobTask(AsyncExportJob job) { public SendExportJobTask(AsyncExportJob job) {
this.job = job; this.job = job;
} }
/** /**
* This methods performs the actual send operation asynchronously in a separate send thread. * This methods performs the actual send operation asynchronously in a separate send thread.
* Job status listeners will be notified once the operation finishes or fails. * Job status listeners will be notified once the operation finishes or fails.
*/ */
@Override @Override
public void run() { public void run() {
try { try {
HTTPConnection connector = (HTTPConnection) job.getConnector(); HTTPConnection connector = (HTTPConnection) job.getConnector();
connector.sendAndUpdateExportJob(job); connector.sendAndUpdateExportJob(job);
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!");
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
signalError("The job transmission failed. There seams to be a problem with the connector!"); signalError("The job transmission failed. There seams to be a problem with the connector!");
} }
} }
/** /**
* This method is superfluous I guess? TODO: Please check and 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.UNKNOWN, Optional.of(errorMessage)); job.setStatus(JobStatus.UNKNOWN, Optional.of(errorMessage));
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import java.util.Optional; import java.util.Optional;
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;
/** /**
* This task sends an import job to your nF server asynchronously within a separate send thread. Once the send * This task sends an import job to your nF server asynchronously within a separate send thread. Once the send
* operation has finished all of the jobs status listeners will be notified. You can cancel this task by calling * operation has finished all of the jobs status listeners will be notified. You can cancel this task by calling
* job.cancel(). * job.cancel().
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class SendImportJobTask implements Runnable { public class SendImportJobTask implements Runnable {
/** The job to be sent to your nF server. */ /** The job to be sent to your nF server. */
private AsyncImportJob job; private AsyncImportJob job;
/** /**
* Constructor with the import job to be sent. * Constructor with the import job to be sent.
* *
* @param job The import job to be sent. * @param job The import job to be sent.
*/ */
public SendImportJobTask(AsyncImportJob job) { public SendImportJobTask(AsyncImportJob job) {
this.job = job; this.job = job;
} }
/** /**
* This methods performs the actual send operation asynchronously in a separate send thread. * This methods performs the actual send operation asynchronously in a separate send thread.
* Job status listeners will be notified once the operation finishes or fails. * Job status listeners will be notified once the operation finishes or fails.
*/ */
@Override @Override
public void run() { public void run() {
try { try {
HTTPConnection connector = (HTTPConnection) job.getConnector(); HTTPConnection connector = (HTTPConnection) job.getConnector();
connector.sendAndUpdateImportJob(job); connector.sendAndUpdateImportJob(job);
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!");
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
signalError("The job transmission failed. There seams to be a problem with the connector!"); signalError("The job transmission failed. There seams to be a problem with the connector!");
} }
} }
/** /**
* This method is superfluous I guess? TODO: Please check and 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.UNKNOWN, Optional.of(errorMessage)); job.setStatus(JobStatus.UNKNOWN, Optional.of(errorMessage));
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
/** /**
* Units (Blattschnitte) divide regions into sections. For instance, the city of Stuttgart could have the units * Units (Blattschnitte) divide regions into sections. For instance, the city of Stuttgart could have the units
* "Stg-Mitte", "Stg-West", "Bad Cannstatt", "Heslach", etc. * "Stg-Mitte", "Stg-West", "Bad Cannstatt", "Heslach", etc.
* *
* @author Marcel Bruse * @author Marcel Bruse
* *
*/ */
public class Unit { public class Unit {
private static final String DEFAULT_EXTERIOR = "0"; private static final String DEFAULT_EXTERIOR = "0";
private static final String DEFAULT_FRAME = "0"; private static final String DEFAULT_FRAME = "0";
private static final String DEFAULT_SELECT_MAP_SHEETS = "0"; private static final String DEFAULT_SELECT_MAP_SHEETS = "0";
private static final String DEFAULT_SUBDIVISION = "4"; private static final String DEFAULT_SUBDIVISION = "4";
/** The exterior attribute of the unit tag. */ /** The exterior attribute of the unit tag. */
private String exterior; private String exterior;
/** The frame attribute of the unit tag. */ /** The frame attribute of the unit tag. */
private String frame; private String frame;
/** The select mapsheet attribute of the unit tag. */ /** The select mapsheet attribute of the unit tag. */
private String selectMapsheets; private String selectMapsheets;
/** The subdivision attribute of the unit tag. */ /** The subdivision attribute of the unit tag. */
private String subdivision; private String subdivision;
/** The actual value of the unit tag. */ /** The actual value of the unit tag. */
private String value; private String value;
public String getExterior() { public String getExterior() {
return exterior; return exterior;
} }
public void setExterior(String exterior) { public void setExterior(String exterior) {
this.exterior = exterior; this.exterior = exterior;
} }
public String getFrame() { public String getFrame() {
return frame; return frame;
} }
public void setFrame(String frame) { public void setFrame(String frame) {
this.frame = frame; this.frame = frame;
} }
public String getSelectMapsheets() { public String getSelectMapsheets() {
return selectMapsheets; return selectMapsheets;
} }
public void setSelectMapsheets(String selectMapsheets) { public void setSelectMapsheets(String selectMapsheets) {
this.selectMapsheets = selectMapsheets; this.selectMapsheets = selectMapsheets;
} }
public String getSubdivision() { public String getSubdivision() {
return subdivision; return subdivision;
} }
public void setSubdivision(String subdivision) { public void setSubdivision(String subdivision) {
this.subdivision = subdivision; this.subdivision = subdivision;
} }
public String getValue() { public String getValue() {
return value; return value;
} }
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
/** /**
* @return Returns true, if the unit is valid. * @return Returns true, if the unit is valid.
*/ */
public boolean isValid() { public boolean isValid() {
return !(exterior.isEmpty() return !(exterior.isEmpty()
|| frame.isEmpty() || frame.isEmpty()
|| selectMapsheets.isEmpty() || selectMapsheets.isEmpty()
|| subdivision.isEmpty()); || subdivision.isEmpty());
} }
public static Unit getDefaultUnit() { public static Unit getDefaultUnit() {
Unit unit = new Unit(); Unit unit = new Unit();
unit.setExterior(DEFAULT_EXTERIOR); unit.setExterior(DEFAULT_EXTERIOR);
unit.setFrame(DEFAULT_FRAME); unit.setFrame(DEFAULT_FRAME);
unit.setSelectMapsheets(DEFAULT_SELECT_MAP_SHEETS); unit.setSelectMapsheets(DEFAULT_SELECT_MAP_SHEETS);
unit.setSubdivision(DEFAULT_SUBDIVISION); unit.setSubdivision(DEFAULT_SUBDIVISION);
return unit; return unit;
} }
} }
package eu.simstadt.regionchooser; package eu.simstadt.regionchooser;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader; import com.vividsolutions.jts.io.WKTReader;
import com.ximpleware.NavException; import com.ximpleware.NavException;
import com.ximpleware.XPathEvalException; import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException; import com.ximpleware.XPathParseException;
import eu.simstadt.nf4j.ExportJobFromJavaFXRegionChooser; import eu.simstadt.nf4j.ExportJobFromJavaFXRegionChooser;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.concurrent.Worker.State; import javafx.concurrent.Worker.State;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.VPos; import javafx.geometry.VPos;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine; import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView; import javafx.scene.web.WebView;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Stage; import javafx.stage.Stage;
import netscape.javascript.JSObject; import netscape.javascript.JSObject;
public class RegionChooserBrowser extends Region public class RegionChooserBrowser extends Region
{ {
/** /**
* JavaFX Backend for RegionChooser. Inside simstadt_openlayers.js frontend, this class is available as `fxapp`. * JavaFX Backend for RegionChooser. Inside simstadt_openlayers.js frontend, this class is available as `fxapp`.
*/ */
public class JavaScriptFXBridge public class JavaScriptFXBridge
{ {
private Path repo; private Path repo;
private WKTReader wktReader = new WKTReader(); private WKTReader wktReader = new WKTReader();
public JavaScriptFXBridge() { public JavaScriptFXBridge() {
Preferences userPrefs = Preferences.userRoot().node("/eu/simstadt/desktop"); Preferences userPrefs = Preferences.userRoot().node("/eu/simstadt/desktop");
String repoString = userPrefs.get("RECENT_REPOSITORY", null); String repoString = userPrefs.get("RECENT_REPOSITORY", null);
if (repoString == null) { if (repoString == null) {
repo = Paths.get("../TestRepository"); repo = Paths.get("../TestRepository");
} else { } else {
repo = Paths.get(repoString); repo = Paths.get(repoString);
} }
} }
public void downloadRegion(String wktPolygon, String productName, JSObject novaFactoryLayer) public void downloadRegion(String wktPolygon, String productName, JSObject novaFactoryLayer)
throws InterruptedException { throws InterruptedException {
//TODO: Ask nf Server about available regions //TODO: Ask nf Server about available regions
Task<Integer> task = new Task<Integer>() { Task<Integer> task = new Task<Integer>() {
@Override @Override
protected Integer call() throws Exception { protected Integer call() throws Exception {
ExportJobFromJavaFXRegionChooser nfJob = new ExportJobFromJavaFXRegionChooser(); ExportJobFromJavaFXRegionChooser nfJob = new ExportJobFromJavaFXRegionChooser();
Geometry poly = wktReader.read(wktPolygon); Geometry poly = wktReader.read(wktPolygon);
nfJob.processJob(poly, productName, novaFactoryLayer); nfJob.processJob(poly, productName, novaFactoryLayer);
return 0; return 0;
} }
}; };
new Thread(task).start(); new Thread(task).start();
} }
public void extractZIPtoGML(String zipFilename) throws IOException { public void extractZIPtoGML(String zipFilename) throws IOException {
ZipFile zipFile = new ZipFile(zipFilename); ZipFile zipFile = new ZipFile(zipFilename);
Enumeration<? extends ZipEntry> entries = zipFile.entries(); Enumeration<? extends ZipEntry> entries = zipFile.entries();
String userName = System.getProperty("user.name"); String userName = System.getProperty("user.name");
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement(); ZipEntry ze = entries.nextElement();
String zeName = ze.getName(); String zeName = ze.getName();
if (zeName.toLowerCase().contains("gml")) { if (zeName.toLowerCase().contains("gml")) {
File extractedCityGML = selectSaveFileWithDialog(null, File extractedCityGML = selectSaveFileWithDialog(null,
zeName.replace("_GML.", ".").replace(userName, "novaFACTORY"), ""); zeName.replace("_GML.", ".").replace(userName, "novaFACTORY"), "");
if (extractedCityGML != null) { if (extractedCityGML != null) {
InputStream cityGMLInputStream = zipFile.getInputStream(ze); InputStream cityGMLInputStream = zipFile.getInputStream(ze);
BufferedReader cityGMLZipReader = new BufferedReader(new InputStreamReader(cityGMLInputStream)); BufferedReader cityGMLZipReader = new BufferedReader(new InputStreamReader(cityGMLInputStream));
BufferedWriter cityGMLOutput = Files.newBufferedWriter(extractedCityGML.toPath()); BufferedWriter cityGMLOutput = Files.newBufferedWriter(extractedCityGML.toPath());
String buf = null; String buf = null;
while ((buf = cityGMLZipReader.readLine()) != null) { while ((buf = cityGMLZipReader.readLine()) != null) {
cityGMLOutput.write(buf.replace("srsName=\"\"", "srsName=\"EPSG:31467\"")); //TODO: Get EPSG:id from NovaFactory Server? cityGMLOutput.write(buf.replace("srsName=\"\"", "srsName=\"EPSG:31467\"")); //TODO: Get EPSG:id from NovaFactory Server?
} }
cityGMLZipReader.close(); cityGMLZipReader.close();
cityGMLInputStream.close(); cityGMLInputStream.close();
cityGMLOutput.close(); cityGMLOutput.close();
System.out.println("Extracted"); System.out.println("Extracted");
} }
} }
} }
zipFile.close(); zipFile.close();
} }
public void downloadRegionFromCityGML(String wktPolygon, String project, String citygml, String srsName) public void downloadRegionFromCityGML(String wktPolygon, String project, String citygml, String srsName)
throws IOException, ParseException, SAXParseException, XMLStreamException, NumberFormatException, throws IOException, ParseException, SAXParseException, XMLStreamException, NumberFormatException,
XPathParseException, NavException, XPathEvalException { XPathParseException, NavException, XPathEvalException {
StringBuffer sb = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath(project, citygml), wktPolygon, StringBuffer sb = RegionExtractor.selectRegionDirectlyFromCityGML(citygmlPath(project, citygml), wktPolygon,
srsName); srsName);
File buildingIdsFile = selectSaveFileWithDialog(project, citygml, "selected_region"); File buildingIdsFile = selectSaveFileWithDialog(project, citygml, "selected_region");
if (buildingIdsFile != null) { if (buildingIdsFile != null) {
BufferedWriter writer = Files.newBufferedWriter(buildingIdsFile.toPath()); BufferedWriter writer = Files.newBufferedWriter(buildingIdsFile.toPath());
writer.write(sb.toString()); writer.write(sb.toString());
writer.close(); writer.close();
} }
} }
private File selectSaveFileWithDialog(String project, String citygml, String suffix) { private File selectSaveFileWithDialog(String project, String citygml, String suffix) {
Stage mainStage = (Stage) RegionChooserBrowser.this.getScene().getWindow(); Stage mainStage = (Stage) RegionChooserBrowser.this.getScene().getWindow();
FileChooser fileChooser = new FileChooser(); FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save CITYGML ids"); fileChooser.setTitle("Save CITYGML ids");
if (project != null) { if (project != null) {
fileChooser.setInitialDirectory(repo.resolve(project + ".proj").toFile()); fileChooser.setInitialDirectory(repo.resolve(project + ".proj").toFile());
} else { } else {
fileChooser.setInitialDirectory(repo.toFile()); fileChooser.setInitialDirectory(repo.toFile());
} }
if (suffix.isEmpty()) { if (suffix.isEmpty()) {
fileChooser.setInitialFileName(citygml); fileChooser.setInitialFileName(citygml);
} else { } else {
fileChooser.setInitialFileName(citygml.replace(".", "_" + suffix + ".")); fileChooser.setInitialFileName(citygml.replace(".", "_" + suffix + "."));
} }
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("GML files (*.gml)", "*.gml"); FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("GML files (*.gml)", "*.gml");
fileChooser.getExtensionFilters().add(extFilter); fileChooser.getExtensionFilters().add(extFilter);
return fileChooser.showSaveDialog(mainStage); return fileChooser.showSaveDialog(mainStage);
} }
public boolean checkIfCityGMLSAreAvailable(String project, String citygml) { public boolean checkIfCityGMLSAreAvailable(String project, String citygml) {
Path p = citygmlPath(project, citygml); Path p = citygmlPath(project, citygml);
return Files.isReadable(p); return Files.isReadable(p);
} }
public void log(String text) { public void log(String text) {
System.out.println(text); System.out.println(text);
} }
private Path citygmlPath(String project, String citygml) { private Path citygmlPath(String project, String citygml) {
return repo.resolve(project + ".proj").resolve(citygml); return repo.resolve(project + ".proj").resolve(citygml);
} }
public void importNovaFactoryBoundingBoxes() throws IOException { public void importNovaFactoryBoundingBoxes() throws IOException {
JSObject novafactoryVectors = (JSObject) webEngine.executeScript("novafactory_vectors"); JSObject novafactoryVectors = (JSObject) webEngine.executeScript("novafactory_vectors");
BufferedReader nf_csv = new BufferedReader(new InputStreamReader( BufferedReader nf_csv = new BufferedReader(new InputStreamReader(
RegionChooserFX.class.getResourceAsStream("website/data/novafactory_products.csv"))); RegionChooserFX.class.getResourceAsStream("website/data/novafactory_products.csv")));
nf_csv.readLine(); nf_csv.readLine();
String sCurrentLine; String sCurrentLine;
while ((sCurrentLine = nf_csv.readLine()) != null) { while ((sCurrentLine = nf_csv.readLine()) != null) {
String[] values = sCurrentLine.trim().split(","); String[] values = sCurrentLine.trim().split(",");
String product = values[1]; String product = values[1];
// String description = values[2]; // String description = values[2];
String[] srs = values[3].split(" "); String[] srs = values[3].split(" ");
String epsgId = srs[srs.length - 1]; String epsgId = srs[srs.length - 1];
// System.out.println(product); // System.out.println(product);
novafactoryVectors.call("addNovaFactoryProduct", values[8], values[9], values[10], values[11], product, novafactoryVectors.call("addNovaFactoryProduct", values[8], values[9], values[10], values[11], product,
epsgId); epsgId);
} }
nf_csv.close(); nf_csv.close();
} }
} }
final WebView browser = new WebView(); final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine(); final WebEngine webEngine = browser.getEngine();
public RegionChooserBrowser() { public RegionChooserBrowser() {
//apply the styles //apply the styles
getStyleClass().add("browser"); getStyleClass().add("browser");
String url = RegionChooserFX.class.getResource("website/index.html").toExternalForm(); String url = RegionChooserFX.class.getResource("website/index.html").toExternalForm();
webEngine.load(url); // load the web page webEngine.load(url); // load the web page
// process page loading // process page loading
webEngine.getLoadWorker().stateProperty().addListener( webEngine.getLoadWorker().stateProperty().addListener(
(ObservableValue<? extends State> ov, State oldState, State newState) -> { (ObservableValue<? extends State> ov, State oldState, State newState) -> {
if (newState == State.SUCCEEDED) { if (newState == State.SUCCEEDED) {
JSObject win = (JSObject) webEngine.executeScript("window"); JSObject win = (JSObject) webEngine.executeScript("window");
JavaScriptFXBridge fxapp = new JavaScriptFXBridge(); JavaScriptFXBridge fxapp = new JavaScriptFXBridge();
win.setMember("fxapp", fxapp); win.setMember("fxapp", fxapp);
webEngine.executeScript("console.log = function(message)\n" + webEngine.executeScript("console.log = function(message)\n" +
"{\n" + "{\n" +
" fxapp.log(message);\n" + " fxapp.log(message);\n" +
"};"); "};");
try { try {
fxapp.importNovaFactoryBoundingBoxes(); fxapp.importNovaFactoryBoundingBoxes();
} catch (Exception ex) { } catch (Exception ex) {
RegionChooserFX.LOGGER.warning("NovaFactory CSV not found or corrupt"); RegionChooserFX.LOGGER.warning("NovaFactory CSV not found or corrupt");
ex.printStackTrace(); ex.printStackTrace();
} }
// try { // try {
// fxapp.selectRegionDirectlyFromCityGML( // fxapp.selectRegionDirectlyFromCityGML(
// Paths.get("../TestRepository").resolve("Gruenbuehl.proj") // Paths.get("../TestRepository").resolve("Gruenbuehl.proj")
// .resolve("Gruenbuehl_LOD2_validated+ADE.gml"), // .resolve("Gruenbuehl_LOD2_validated+ADE.gml"),
// "POLYGON((3515896.6132767177 5415942.563662692,3516013.1135652466 5415930.341095623,3516035.1608944996 5415925.696283888,3516052.531667652 5415905.3452489935,3516053.640043498 5415793.1428597355,3516092.996199113 5415790.117097386,3516086.9957373445 5415687.30812527,3515953.2106800284 5415687.710348818,3515893.4419519473 5415673.416324939,3515876.73573549 5415736.92758554,3515896.6132767177 5415942.563662692))" // "POLYGON((3515896.6132767177 5415942.563662692,3516013.1135652466 5415930.341095623,3516035.1608944996 5415925.696283888,3516052.531667652 5415905.3452489935,3516053.640043498 5415793.1428597355,3516092.996199113 5415790.117097386,3516086.9957373445 5415687.30812527,3515953.2106800284 5415687.710348818,3515893.4419519473 5415673.416324939,3515876.73573549 5415736.92758554,3515896.6132767177 5415942.563662692))"
// ); // );
// } catch (Exception ex) { // } catch (Exception ex) {
// ex.printStackTrace(); // ex.printStackTrace();
// //
// } // }
// System.exit(0); // System.exit(0);
} }
}); });
//add the web view to the scene //add the web view to the scene
getChildren().add(browser); getChildren().add(browser);
} }
@Override @Override
protected void layoutChildren() { protected void layoutChildren() {
double w = getWidth(); double w = getWidth();
double h = getHeight(); double h = getHeight();
layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER); layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
} }
@Override @Override
protected double computePrefWidth(double height) { protected double computePrefWidth(double height) {
return 900; return 900;
} }
@Override @Override
protected double computePrefHeight(double width) { protected double computePrefHeight(double width) {
return 600; return 600;
} }
} }
package eu.simstadt.regionchooser; package eu.simstadt.regionchooser;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader; import com.vividsolutions.jts.io.WKTReader;
import com.ximpleware.NavException; import com.ximpleware.NavException;
import com.ximpleware.XPathEvalException; import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException; import com.ximpleware.XPathParseException;
import eu.simstadt.geo.fast_xml_parser.BuildingXmlNode; import eu.simstadt.geo.fast_xml_parser.BuildingXmlNode;
import eu.simstadt.geo.fast_xml_parser.CityGmlIterator; import eu.simstadt.geo.fast_xml_parser.CityGmlIterator;
public class RegionExtractor public class RegionExtractor
{ {
private static final WKTReader wktReader = new WKTReader(); private static final WKTReader wktReader = new WKTReader();
private static final Logger LOGGER = Logger.getLogger(RegionExtractor.class.getName()); private static final Logger LOGGER = Logger.getLogger(RegionExtractor.class.getName());
private static final GeometryFactory gf = new GeometryFactory(); private static final GeometryFactory gf = new GeometryFactory();
/** /**
* Main method behind RegionChooser. Given a CityGML (as Path) and a geometry (as Well-known text POLYGON, in the * Main method behind RegionChooser. Given a CityGML (as Path) and a geometry (as Well-known text POLYGON, in the
* same coordinate system as the CityGML), it iterates over each Building and checks if the building is inside the * same coordinate system as the CityGML), it iterates over each Building and checks if the building is inside the
* geometry. It only works with CityGML files smaller than 2GB. It uses VTD-XML parser instead of a whole * geometry. It only works with CityGML files smaller than 2GB. It uses VTD-XML parser instead of a whole
* Simstadt/Citydoctor/Citygml model. * Simstadt/Citydoctor/Citygml model.
* *
* *
* @param citygmlPath * @param citygmlPath
* @param wktPolygon * @param wktPolygon
* @param string * @param string
* @return a StringBuffer, full with the extracted Citygml, including header, buildings and footer. * @return a StringBuffer, full with the extracted Citygml, including header, buildings and footer.
* @throws ParseException * @throws ParseException
* @throws IOException * @throws IOException
* @throws XPathEvalException * @throws XPathEvalException
* @throws NavException * @throws NavException
* @throws XPathParseException * @throws XPathParseException
* @throws NumberFormatException * @throws NumberFormatException
*/ */
static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, String wktPolygon, String srsName) static public StringBuffer selectRegionDirectlyFromCityGML(Path citygmlPath, String wktPolygon, String srsName)
throws ParseException, NumberFormatException, XPathParseException, NavException, XPathEvalException, throws ParseException, NumberFormatException, XPathParseException, NavException, XPathEvalException,
IOException { IOException {
int buildingsCount = 0; int buildingsCount = 0;
int foundBuildingsCount = 0; int foundBuildingsCount = 0;
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
Geometry poly = wktReader.read(wktPolygon); Geometry poly = wktReader.read(wktPolygon);
CityGmlIterator citygml = new CityGmlIterator(citygmlPath); CityGmlIterator citygml = new CityGmlIterator(citygmlPath);
for (BuildingXmlNode buildingXmlNode : citygml) { for (BuildingXmlNode buildingXmlNode : citygml) {
if (buildingsCount == 0) { if (buildingsCount == 0) {
sb.append(replaceEnvelopeInHeader(citygml.getHeader(), poly.getEnvelopeInternal(), srsName)); sb.append(replaceEnvelopeInHeader(citygml.getHeader(), poly.getEnvelopeInternal(), srsName));
} }
buildingsCount += 1; buildingsCount += 1;
Coordinate coord = new Coordinate(buildingXmlNode.x, buildingXmlNode.y); Coordinate coord = new Coordinate(buildingXmlNode.x, buildingXmlNode.y);
Point point = gf.createPoint(coord); Point point = gf.createPoint(coord);
if (point.within(poly)) { if (point.within(poly)) {
foundBuildingsCount++; foundBuildingsCount++;
sb.append(buildingXmlNode.toString()); sb.append(buildingXmlNode.toString());
} }
if (buildingsCount % 1000 == 0) { if (buildingsCount % 1000 == 0) {
LOGGER.info("1000 buildings parsed"); LOGGER.info("1000 buildings parsed");
} }
} }
LOGGER.info("Buildings found in selected region " + foundBuildingsCount); LOGGER.info("Buildings found in selected region " + foundBuildingsCount);
sb.append(citygml.getFooter()); sb.append(citygml.getFooter());
return sb; return sb;
} }
/** /**
* Some Citygml files include an envelope (bounding box), defined at the very beginning of the file. If the extracted * Some Citygml files include an envelope (bounding box), defined at the very beginning of the file. If the extracted
* region comes from a huge file (e.g. from NYC), it might inherit this header with a huge envelope. Some methods * region comes from a huge file (e.g. from NYC), it might inherit this header with a huge envelope. Some methods
* might get confused by this wrong envelope, so this method replaces the original envelope with the bounding box * might get confused by this wrong envelope, so this method replaces the original envelope with the bounding box
* from the extracting polygon. The real envelope might be even smaller, but it could only be known at the end of the * from the extracting polygon. The real envelope might be even smaller, but it could only be known at the end of the
* parsing, after having analyzed every building. The envelope should be written in the header. If present, min and * parsing, after having analyzed every building. The envelope should be written in the header. If present, min and
* max values for Z are kept. * max values for Z are kept.
* *
* @param header * @param header
* @param envelope * @param envelope
* @param srsName * @param srsName
* @return CityGML Header with an updated envelope * @return CityGML Header with an updated envelope
*/ */
private static String replaceEnvelopeInHeader(String header, Envelope envelope, String srsName) { private static String replaceEnvelopeInHeader(String header, Envelope envelope, String srsName) {
//NOTE: Sorry for using a regex to parse XML. The header in itself isn't a valid XML, so this looked like the easiest solution. //NOTE: Sorry for using a regex to parse XML. The header in itself isn't a valid XML, so this looked like the easiest solution.
double zMin = 0; double zMin = 0;
double zMax = 0; double zMax = 0;
Pattern boundedByPattern = Pattern.compile( Pattern boundedByPattern = Pattern.compile(
"(?is)<gml:boundedBy>.*?<gml:lowerCorner>(.*?)</gml:lowerCorner>\\s*<gml:upperCorner>(.*?)</gml:upperCorner>.*?</gml:boundedBy>"); "(?is)<gml:boundedBy>.*?<gml:lowerCorner>(.*?)</gml:lowerCorner>\\s*<gml:upperCorner>(.*?)</gml:upperCorner>.*?</gml:boundedBy>");
Matcher matcher = boundedByPattern.matcher(header); Matcher matcher = boundedByPattern.matcher(header);
String headerWithoutEnvelope = header; String headerWithoutEnvelope = header;
if (matcher.find()) { if (matcher.find()) {
headerWithoutEnvelope = matcher.replaceFirst(""); headerWithoutEnvelope = matcher.replaceFirst("");
zMin = Double.valueOf(matcher.group(1).split("\\s+")[2]); zMin = Double.valueOf(matcher.group(1).split("\\s+")[2]);
zMax = Double.valueOf(matcher.group(2).split("\\s+")[2]); zMax = Double.valueOf(matcher.group(2).split("\\s+")[2]);
} }
String newEnvelope = "<gml:boundedBy>\r\n" + String newEnvelope = "<gml:boundedBy>\r\n" +
" <gml:Envelope srsName=\"" + srsName + "\" srsDimension=\"3\">\r\n" + //NOTE: Would srsDimension="2" be better? Should the original Z get extracted? " <gml:Envelope srsName=\"" + srsName + "\" srsDimension=\"3\">\r\n" + //NOTE: Would srsDimension="2" be better? Should the original Z get extracted?
" <gml:lowerCorner>" + envelope.getMinX() + " " + envelope.getMinY() + " " + zMin " <gml:lowerCorner>" + envelope.getMinX() + " " + envelope.getMinY() + " " + zMin
+ "</gml:lowerCorner>\r\n" + + "</gml:lowerCorner>\r\n" +
" <gml:upperCorner>" + envelope.getMaxX() + " " + envelope.getMaxY() + " " + zMax " <gml:upperCorner>" + envelope.getMaxX() + " " + envelope.getMaxY() + " " + zMax
+ "</gml:upperCorner>\r\n" + + "</gml:upperCorner>\r\n" +
" </gml:Envelope>\r\n" + " </gml:Envelope>\r\n" +
"</gml:boundedBy>\r\n"; "</gml:boundedBy>\r\n";
return headerWithoutEnvelope + newEnvelope; return headerWithoutEnvelope + newEnvelope;
} }
} }
//TODO: Clean up code and don't leave so many global variables //TODO: Clean up code and don't leave so many global variables
var reset_btn = $('#reset')[0]; var reset_btn = $('#reset')[0];
var dataPanel = $('#dataPanel'); var dataPanel = $('#dataPanel');
var wgs84Sphere = new ol.Sphere(6378137); var wgs84Sphere = new ol.Sphere(6378137);
proj4.defs("EPSG:3068", "+proj=cass +lat_0=52.41864827777778 +lon_0=13.62720366666667 +x_0=40000 +y_0=10000 +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/3068/proj4js/ proj4.defs("EPSG:3068", "+proj=cass +lat_0=52.41864827777778 +lon_0=13.62720366666667 +x_0=40000 +y_0=10000 +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/3068/proj4js/
proj4.defs("EPSG:32632", "+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"); // http://spatialreference.org/ref/epsg/32632/proj4js/ proj4.defs("EPSG:32632", "+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"); // http://spatialreference.org/ref/epsg/32632/proj4js/
proj4.defs("EPSG:31463", "+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0" + " +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/31463/proj4js/ proj4.defs("EPSG:31463", "+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0" + " +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/31463/proj4js/
proj4.defs("EPSG:31467", "+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0" + " +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/31467/proj4js/ proj4.defs("EPSG:31467", "+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0" + " +ellps=bessel +datum=potsdam +units=m +no_defs"); // http://spatialreference.org/ref/epsg/31467/proj4js/
proj4.defs("EPSG:32118", "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs"); // http://spatialreference.org/ref/epsg/32118/proj4js/ proj4.defs("EPSG:32118", "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs"); // http://spatialreference.org/ref/epsg/32118/proj4js/
proj4.defs("EPSG:2263", "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs "); // http://www.spatialreference.org/ref/epsg/nad83-new-york-long-island-ftus/proj4/ proj4.defs("EPSG:2263", "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs "); // http://www.spatialreference.org/ref/epsg/nad83-new-york-long-island-ftus/proj4/
//NOTE: Proj4 string for 28992 is wrong at http://spatialreference.org/ref/epsg/amersfoort-rd-new/ //NOTE: Proj4 string for 28992 is wrong at http://spatialreference.org/ref/epsg/amersfoort-rd-new/
//NOTE: Corrected version from https://oegeo.wordpress.com/2008/05/20/note-to-self-the-one-and-only-rd-projection-string/ //NOTE: Corrected version from https://oegeo.wordpress.com/2008/05/20/note-to-self-the-one-and-only-rd-projection-string/
proj4.defs("EPSG:28992", "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.999908 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.2369,50.0087,465.658,-0.406857330322398,0.350732676542563,-1.8703473836068,4.0812 +no_defs <>"); // proj4.defs("EPSG:28992", "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.999908 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.2369,50.0087,465.658,-0.406857330322398,0.350732676542563,-1.8703473836068,4.0812 +no_defs <>"); //
var osm_layer = new ol.layer.Tile({ var osm_layer = new ol.layer.Tile({
source: new ol.source.OSM() source: new ol.source.OSM()
}); });
var kml_source = new ol.source.KML({ var kml_source = new ol.source.KML({
projection : ol.proj.get('EPSG:3857'), projection : ol.proj.get('EPSG:3857'),
url : 'data/citygml_hulls.kml', url : 'data/citygml_hulls.kml',
extractAttributes : false, extractAttributes : false,
extractStyles : false extractStyles : false
}); });
function polygon_style(color, alpha) { function polygon_style(color, alpha) {
return new ol.style.Style({ return new ol.style.Style({
fill : new ol.style.Fill({ fill : new ol.style.Fill({
color : 'rgba(255, 255, 255,' + alpha + ')' color : 'rgba(255, 255, 255,' + alpha + ')'
}), }),
stroke : new ol.style.Stroke({ stroke : new ol.style.Stroke({
color : color, color : color,
width : 2, width : 2,
lineDash : [ 5, 10 ] lineDash : [ 5, 10 ]
}), }),
}); });
} }
var kml_layer = new ol.layer.Vector({ var kml_layer = new ol.layer.Vector({
source : kml_source, source : kml_source,
style : polygon_style('#777777', 0.2) style : polygon_style('#777777', 0.2)
}); });
var intersections = new ol.source.Vector(); var intersections = new ol.source.Vector();
var intersections_layer = new ol.layer.Vector({ var intersections_layer = new ol.layer.Vector({
source : intersections, source : intersections,
style : new ol.style.Style({ style : new ol.style.Style({
fill : new ol.style.Fill({ fill : new ol.style.Fill({
color : 'rgba(255, 155, 51, 0.2)' color : 'rgba(255, 155, 51, 0.2)'
}) })
}) })
}); });
var novafactory_vectors = new ol.source.Vector({ var novafactory_vectors = new ol.source.Vector({
features : [] features : []
}); });
novafactory_vectors.addNovaFactoryProduct = function(xmin, ymin, xmax, ymax, name, epsgId) { novafactory_vectors.addNovaFactoryProduct = function(xmin, ymin, xmax, ymax, name, epsgId) {
var box = new ol.geom.Polygon( var box = new ol.geom.Polygon(
[ [ [ xmin, ymin ], [ xmin, ymax ], [ xmax, ymax ], [ xmax, ymin ], [ xmin, ymin ] ] ]); [ [ [ xmin, ymin ], [ xmin, ymax ], [ xmax, ymax ], [ xmax, ymin ], [ xmin, ymin ] ] ]);
box.transform('EPSG:' + epsgId, 'EPSG:3857'); box.transform('EPSG:' + epsgId, 'EPSG:3857');
var feature = new ol.Feature({ var feature = new ol.Feature({
geometry : box, geometry : box,
name : name, name : name,
}); });
feature["geoJSON"] = geoJSONformat.writeFeatureObject(feature); feature["geoJSON"] = geoJSONformat.writeFeatureObject(feature);
feature["area"] = feature.getGeometry().getArea(); feature["area"] = feature.getGeometry().getArea();
feature["description"] = "novaFACTORY>" + name; feature["description"] = "novaFACTORY>" + name;
feature["available"] = true; feature["available"] = true;
feature["source"] = "NovaFACTORY"; feature["source"] = "NovaFACTORY";
this.addFeature(feature); this.addFeature(feature);
}; };
var novafactory_layer = new ol.layer.Vector({ var novafactory_layer = new ol.layer.Vector({
source : novafactory_vectors, source : novafactory_vectors,
style : polygon_style('#ff7700', 0.1) style : polygon_style('#ff7700', 0.1)
}); });
var map = new ol.Map({ var map = new ol.Map({
target : 'map', target : 'map',
layers : [ osm_layer, kml_layer, novafactory_layer, intersections_layer ], layers : [ osm_layer, kml_layer, novafactory_layer, intersections_layer ],
interactions : ol.interaction.defaults({ interactions : ol.interaction.defaults({
keyboard : true keyboard : true
}) })
}); });
var geoJSONformat = new ol.format.GeoJSON(); var geoJSONformat = new ol.format.GeoJSON();
kml_layer.addEventListener("change", function() { kml_layer.addEventListener("change", function() {
map.getView().fitExtent(kml_source.getExtent(), (map.getSize())); map.getView().fitExtent(kml_source.getExtent(), (map.getSize()));
}); });
function updateGMLPolygons() { function updateGMLPolygons() {
kml_source.forEachFeature(function(feature) { kml_source.forEachFeature(function(feature) {
feature["geoJSON"] = geoJSONformat.writeFeatureObject(feature); feature["geoJSON"] = geoJSONformat.writeFeatureObject(feature);
feature["area"] = feature.getGeometry().getArea(); feature["area"] = feature.getGeometry().getArea();
var project = feature.get("project"); var project = feature.get("project");
var name = feature.get("name"); var name = feature.get("name");
feature["description"] = project + ">" + name; feature["description"] = project + ">" + name;
feature["source"] = "CityGML"; feature["source"] = "CityGML";
var citygmlHere; var citygmlHere;
if (fromJavaFX) { if (fromJavaFX) {
citygmlHere = fxapp.checkIfCityGMLSAreAvailable(project, name); citygmlHere = fxapp.checkIfCityGMLSAreAvailable(project, name);
} }
feature["available"] = citygmlHere; feature["available"] = citygmlHere;
}); });
} }
// The features are not added to a regular vector layer/source, // The features are not added to a regular vector layer/source,
// but to a feature overlay which holds a collection of features. // but to a feature overlay which holds a collection of features.
// This collection is passed to the modify and also the draw // This collection is passed to the modify and also the draw
// interaction, so that both can add or modify features. // interaction, so that both can add or modify features.
var featureOverlay = new ol.FeatureOverlay({ var featureOverlay = new ol.FeatureOverlay({
style : new ol.style.Style({ style : new ol.style.Style({
fill : new ol.style.Fill({ fill : new ol.style.Fill({
color : 'rgba(255, 155, 51, 0.5)' color : 'rgba(255, 155, 51, 0.5)'
}), }),
stroke : new ol.style.Stroke({ stroke : new ol.style.Stroke({
color : '#ffcc33', color : '#ffcc33',
width : 4 width : 4
}), }),
image : new ol.style.Circle({ image : new ol.style.Circle({
radius : 5, radius : 5,
fill : new ol.style.Fill({ fill : new ol.style.Fill({
color : '#ffcc33' color : '#ffcc33'
}) })
}) })
}) })
}); });
featureOverlay.setMap(map); featureOverlay.setMap(map);
var selected_features = featureOverlay.getFeatures(); var selected_features = featureOverlay.getFeatures();
selected_features.on('add', function(event) { selected_features.on('add', function(event) {
var feature = event.element; var feature = event.element;
feature.on("change", function() { feature.on("change", function() {
displayInfo(); displayInfo();
}); });
}); });
var modify = new ol.interaction.Modify({ var modify = new ol.interaction.Modify({
features : featureOverlay.getFeatures(), features : featureOverlay.getFeatures(),
// the SHIFT key must be pressed to delete vertices, so // the SHIFT key must be pressed to delete vertices, so
// that new vertices can be drawn at the same position // that new vertices can be drawn at the same position
// of existing vertices // of existing vertices
deleteCondition : function(event) { deleteCondition : function(event) {
return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.singleClick(event); return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.singleClick(event);
} }
}); });
map.addInteraction(modify); map.addInteraction(modify);
var draw = new ol.interaction.Draw({ var draw = new ol.interaction.Draw({
features : featureOverlay.getFeatures(), features : featureOverlay.getFeatures(),
type : 'Polygon' type : 'Polygon'
}); });
map.addInteraction(draw); map.addInteraction(draw);
var sketch; var sketch;
var fromJavaFX; var fromJavaFX;
draw.on('drawstart', function(evt) { draw.on('drawstart', function(evt) {
fromJavaFX = (typeof fxapp !== 'undefined'); fromJavaFX = (typeof fxapp !== 'undefined');
sketch = evt.feature; sketch = evt.feature;
reset_btn.disabled = false; reset_btn.disabled = false;
updateGMLPolygons(); updateGMLPolygons();
}); });
var sourceProj = map.getView().getProjection(); var sourceProj = map.getView().getProjection();
function findIntersections() { function findIntersections() {
var sketch_area = sketch.getGeometry().getArea(); var sketch_area = sketch.getGeometry().getArea();
var poly1 = geoJSONformat.writeFeatureObject(sketch); var poly1 = geoJSONformat.writeFeatureObject(sketch);
var intersection_found = false; var intersection_found = false;
intersections.clear(); intersections.clear();
function findIntersection(feature) { function findIntersection(feature) {
try { try {
var jsonIntersection = turf.intersect(poly1, feature["geoJSON"]); var jsonIntersection = turf.intersect(poly1, feature["geoJSON"]);
if (undefined !== jsonIntersection) { if (undefined !== jsonIntersection) {
if (!intersection_found) { if (!intersection_found) {
dataPanel.append("Intersection found with :<br/>\n"); dataPanel.append("Intersection found with :<br/>\n");
intersection_found = true; intersection_found = true;
} }
var intersection = geoJSONformat.readFeature(jsonIntersection); var intersection = geoJSONformat.readFeature(jsonIntersection);
var intersectionArea = intersection.getGeometry().getArea(); var intersectionArea = intersection.getGeometry().getArea();
var citygml_percentage = Math.round(intersectionArea / feature["area"] * 100); var citygml_percentage = Math.round(intersectionArea / feature["area"] * 100);
var sketch_percentage = Math.round(intersectionArea / sketch_area * 100); var sketch_percentage = Math.round(intersectionArea / sketch_area * 100);
intersections.addFeature(intersection); intersections.addFeature(intersection);
var description; var description;
if (feature["available"]) { if (feature["available"]) {
description = "<a href=\"#\" onclick=\"downloadRegionFrom" + feature["source"] + "(" + i description = "<a href=\"#\" onclick=\"downloadRegionFrom" + feature["source"] + "(" + i
+ ");return false;\">" + feature["description"] + "</a>"; + ");return false;\">" + feature["description"] + "</a>";
// console.log(description); // console.log(description);
} else { } else {
description = feature['description']; description = feature['description'];
} }
dataPanel.append(description + " (" + citygml_percentage + "%"); dataPanel.append(description + " (" + citygml_percentage + "%");
if (sketch_percentage == 100) { if (sketch_percentage == 100) {
dataPanel.append(", all inside"); dataPanel.append(", all inside");
} }
dataPanel.append(")<br/>\n"); dataPanel.append(")<br/>\n");
} }
} catch (err) { } catch (err) {
console.log(feature.get('description') + " - " + err); console.log(feature.get('description') + " - " + err);
} }
i++; i++;
} }
var i = 0; var i = 0;
novafactory_vectors.forEachFeature(findIntersection); novafactory_vectors.forEachFeature(findIntersection);
i = 0; i = 0;
kml_source.forEachFeature(findIntersection); kml_source.forEachFeature(findIntersection);
if (!intersection_found) { if (!intersection_found) {
dataPanel.append("No intersection found with any CityGML or NovaFactory product<br/>\n"); dataPanel.append("No intersection found with any CityGML or NovaFactory product<br/>\n");
} }
} }
function downloadRegionFromCityGML(i) { function downloadRegionFromCityGML(i) {
// TODO: Disable all links // TODO: Disable all links
// TODO: DRY // TODO: DRY
var feature = kml_source.getFeatures()[i]; var feature = kml_source.getFeatures()[i];
// Waiting 100ms in order to let the cursor change // Waiting 100ms in order to let the cursor change
setTimeout(function() { setTimeout(function() {
var start = new Date().getTime(); var start = new Date().getTime();
var srsName = feature.get("srsName") || "EPSG:31467"; var srsName = feature.get("srsName") || "EPSG:31467";
if (proj4.defs(srsName)){ if (proj4.defs(srsName)){
$("html").addClass("wait"); $("html").addClass("wait");
console.log("Selected region is written in " + srsName + " coordinate system."); console.log("Selected region is written in " + srsName + " coordinate system.");
fxapp.downloadRegionFromCityGML(sketchAsWKT(srsName), feature.get("project"), feature.get("name"), srsName); fxapp.downloadRegionFromCityGML(sketchAsWKT(srsName), feature.get("project"), feature.get("name"), srsName);
var end = new Date().getTime(); var end = new Date().getTime();
var time = end - start; var time = end - start;
console.log('DL Execution time: ' + time); console.log('DL Execution time: ' + time);
setTimeout(function() { setTimeout(function() {
$("html").removeClass("wait"); $("html").removeClass("wait");
dataPanel.append("Done<br/>\n"); dataPanel.append("Done<br/>\n");
}, 100); }, 100);
} else { } else {
var msg = "ERROR : Unknown coordinate system : \"" + srsName + "\". Cannot extract any region"; var msg = "ERROR : Unknown coordinate system : \"" + srsName + "\". Cannot extract any region";
console.log(msg); console.log(msg);
dataPanel.append(msg + "<br/>\n"); dataPanel.append(msg + "<br/>\n");
} }
}, 100); }, 100);
} }
function displayInfo() { function displayInfo() {
// var start = new Date().getTime(); // var start = new Date().getTime();
dataPanel.empty(); dataPanel.empty();
var geom = /** @type {ol.geom.Polygon} */ var geom = /** @type {ol.geom.Polygon} */
(sketch.getGeometry().clone().transform(sourceProj, 'EPSG:4326')); (sketch.getGeometry().clone().transform(sourceProj, 'EPSG:4326'));
var coordinates = geom.getLinearRing(0).getCoordinates(); var coordinates = geom.getLinearRing(0).getCoordinates();
var area = Math.abs(wgs84Sphere.geodesicArea(coordinates)); var area = Math.abs(wgs84Sphere.geodesicArea(coordinates));
var coords = geom.getLinearRing(0).getCoordinates(); var coords = geom.getLinearRing(0).getCoordinates();
if (!fromJavaFX) { if (!fromJavaFX) {
var wgs84_coords = ""; var wgs84_coords = "";
var n = coords.length; var n = coords.length;
for (var i = 0; i < n; i++) { for (var i = 0; i < n; i++) {
var wgs84_coord = coords[i]; var wgs84_coord = coords[i];
// wgs84_coords += "regionPolygon.add(new Coord(" + wgs84_coord[1] + // wgs84_coords += "regionPolygon.add(new Coord(" + wgs84_coord[1] +
// "," + wgs84_coord[0] + "));<br/>"; // "," + wgs84_coord[0] + "));<br/>";
wgs84_coords += "(" + wgs84_coord[1] + "," + wgs84_coord[0] + ")<br/>"; wgs84_coords += "(" + wgs84_coord[1] + "," + wgs84_coord[0] + ")<br/>";
} }
dataPanel.append("WGS84 Coordinates<br/>"); dataPanel.append("WGS84 Coordinates<br/>");
dataPanel.append(wgs84_coords + "<br/>\n"); dataPanel.append(wgs84_coords + "<br/>\n");
} }
dataPanel.append("Area" + "<br/>\n"); dataPanel.append("Area" + "<br/>\n");
dataPanel.append((Math.round(area / 1000) / 10).toString() + " ha<br/><br/>\n"); dataPanel.append((Math.round(area / 1000) / 10).toString() + " ha<br/><br/>\n");
findIntersections(); findIntersections();
// var end = new Date().getTime(); // var end = new Date().getTime();
// var time = end - start; // var time = end - start;
// console.log('Execution time: ' + time); // console.log('Execution time: ' + time);
} }
draw.on('drawend', function() { draw.on('drawend', function() {
displayInfo(); displayInfo();
draw.setActive(false); draw.setActive(false);
}); });
$('#reset').click(function() { $('#reset').click(function() {
try { try {
draw.finishDrawing(); draw.finishDrawing();
} finally { } finally {
dataPanel.empty(); dataPanel.empty();
$("html").removeClass("wait"); $("html").removeClass("wait");
draw.setActive(true); draw.setActive(true);
featureOverlay.getFeatures().clear(); featureOverlay.getFeatures().clear();
intersections.clear(); intersections.clear();
reset_btn.disabled = true; reset_btn.disabled = true;
focusOnMap(); focusOnMap();
} }
}); });
novafactory_layer.downloadFinished = function() { novafactory_layer.downloadFinished = function() {
// FIXME: Weird <br>s are inserted between lines // FIXME: Weird <br>s are inserted between lines
// FIXME: Doesn't stop waiting cursor // FIXME: Doesn't stop waiting cursor
$("html").removeClass("wait"); $("html").removeClass("wait");
setTimeout(function() { setTimeout(function() {
dataPanel.append("NovaFactory : DONE <br/>\n"); dataPanel.append("NovaFactory : DONE <br/>\n");
}, 100); }, 100);
}; };
novafactory_layer.updateStatus = function(status) { novafactory_layer.updateStatus = function(status) {
dataPanel.append("NovaFactory : " + status + "<br/>\n"); dataPanel.append("NovaFactory : " + status + "<br/>\n");
}; };
novafactory_layer.selectSaveFile = function(zipFilename) { novafactory_layer.selectSaveFile = function(zipFilename) {
fxapp.extractZIPtoGML(zipFilename); fxapp.extractZIPtoGML(zipFilename);
}; };
function downloadRegionFromNovaFACTORY(i) { function downloadRegionFromNovaFACTORY(i) {
$("html").addClass("wait"); $("html").addClass("wait");
var feature = novafactory_vectors.getFeatures()[i]; var feature = novafactory_vectors.getFeatures()[i];
// Waiting 100ms in order to let the cursor change // Waiting 100ms in order to let the cursor change
setTimeout(function() { setTimeout(function() {
fxapp.downloadRegion(sketchAsWKT(), feature.get('name'), novafactory_layer); fxapp.downloadRegion(sketchAsWKT(), feature.get('name'), novafactory_layer);
}, 100); }, 100);
} }
function sketchAsWKT(srsName) { function sketchAsWKT(srsName) {
srsName = (typeof srsName === 'undefined') ? 'EPSG:4326' : srsName; srsName = (typeof srsName === 'undefined') ? 'EPSG:4326' : srsName;
var wktFormat = new ol.format.WKT(); var wktFormat = new ol.format.WKT();
return wktFormat.writeFeature(sketch, { return wktFormat.writeFeature(sketch, {
dataProjection : ol.proj.get(srsName), dataProjection : ol.proj.get(srsName),
featureProjection : ol.proj.get('EPSG:3857') featureProjection : ol.proj.get('EPSG:3857')
}); });
} }
function focusOnMap() { function focusOnMap() {
$('#map').focus(); $('#map').focus();
// $('#map').scrollIntoView(); // $('#map').scrollIntoView();
} }
focusOnMap(); focusOnMap();
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.Scanner; import java.util.Scanner;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import org.junit.Test; import org.junit.Test;
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.AsyncExportJob;
import eu.simstadt.nf4j.async.ExportJobDescription; import eu.simstadt.nf4j.async.ExportJobDescription;
import eu.simstadt.nf4j.async.HTTPConnection; import eu.simstadt.nf4j.async.HTTPConnection;
import eu.simstadt.nf4j.async.JobStatusEvent; import eu.simstadt.nf4j.async.JobStatusEvent;
import eu.simstadt.nf4j.async.JobStatusListener; import eu.simstadt.nf4j.async.JobStatusListener;
import eu.simstadt.nf4j.async.Layer; import eu.simstadt.nf4j.async.Layer;
import eu.simstadt.nf4j.async.Unit; import eu.simstadt.nf4j.async.Unit;
/** /**
* This class contains client oriented export job tests. It will send an export job and listens to status updates. Every * 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 * of the subsequent status' LOCAL, SENT, PENDING, RUNNING, FINISHED and DOWNLOAD have to be signaled to this test
* class. * class.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class SuccessfulExportJob implements JobStatusListener public class SuccessfulExportJob implements JobStatusListener
{ {
public AsyncExportJob job; public AsyncExportJob job;
@Test @Test
public void processJob() throws InterruptedException { public void processJob() throws InterruptedException {
ExportJobDescription description = ExportJobDescription.getDefaultDescriptor(); ExportJobDescription description = ExportJobDescription.getDefaultDescriptor();
description.setInitiator(String.valueOf((int) (Math.random() * 9999))); description.setInitiator(String.valueOf((int) (Math.random() * 9999)));
String userName = System.getProperty("user.name"); String userName = System.getProperty("user.name");
description.setAccount(userName); description.setAccount(userName);
description.setProduct("WU3"); description.setProduct("WU3");
description.setJobnumber(userName); description.setJobnumber(userName);
description.setLODs("2"); description.setLODs("2");
//FIXME: Zipped GMLs coming from nF don't have any defined srsName //FIXME: Zipped GMLs coming from nF don't have any defined srsName
//FIXME: Save files somewhere else //FIXME: Save files somewhere else
//NOTE: Unit is a predefined Map Region. //NOTE: Unit is a predefined Map Region.
// Some of those units are empty. 821 (Finsterrot) and 824 (Neulautern) are available on HFT nF Server. // Some of those units are empty. 821 (Finsterrot) and 824 (Neulautern) are available on HFT nF Server.
// <designation> // <designation>
// 820 // 820
// </designation><name> // </designation><name>
// Wuestenrot // Wuestenrot
// </name></mapsheet><mapsheet nr="127"><designation> // </name></mapsheet><mapsheet nr="127"><designation>
// 821 // 821
// </designation><name> // </designation><name>
// Finsterrot // Finsterrot
// </name></mapsheet><mapsheet nr="128"><designation> // </name></mapsheet><mapsheet nr="128"><designation>
// 822 // 822
// </designation><name> // </designation><name>
// Maienfels // Maienfels
// </name></mapsheet><mapsheet nr="129"><designation> // </name></mapsheet><mapsheet nr="129"><designation>
// 823 // 823
// </designation><name> // </designation><name>
// Neuhütten // Neuhütten
// </name></mapsheet><mapsheet nr="130"><designation> // </name></mapsheet><mapsheet nr="130"><designation>
// 824 // 824
// </designation><name> // </designation><name>
// Neulautern // Neulautern
// </name></mapsheet><mapsheet nr="131"><designation> // </name></mapsheet><mapsheet nr="131"><designation>
// 824-1 // 824-1
// </designation><name> // </designation><name>
// Neulautern (1) // Neulautern (1)
// </name> // </name>
Unit unit = Unit.getDefaultUnit(); Unit unit = Unit.getDefaultUnit();
unit.setValue("824"); unit.setValue("824");
description.addUnit(unit); description.addUnit(unit);
//NOTE: Polygon selection. This would be for a small part of Neulautern //NOTE: Polygon selection. This would be for a small part of Neulautern
// ArrayList<Coord> regionPolygon = new ArrayList<>(); // ArrayList<Coord> regionPolygon = new ArrayList<>();
// regionPolygon.add(new Coord(49.06020829807264, 9.432239985562616)); // regionPolygon.add(new Coord(49.06020829807264, 9.432239985562616));
// regionPolygon.add(new Coord(49.05989193639516, 9.432497477628047)); // regionPolygon.add(new Coord(49.05989193639516, 9.432497477628047));
// regionPolygon.add(new Coord(49.05968102749148, 9.432883715726192)); // regionPolygon.add(new Coord(49.05968102749148, 9.432883715726192));
// regionPolygon.add(new Coord(49.05935060174289, 9.433001732922845)); // regionPolygon.add(new Coord(49.05935060174289, 9.433001732922845));
// regionPolygon.add(new Coord(49.058422585764504, 9.433066105939206)); // regionPolygon.add(new Coord(49.058422585764504, 9.433066105939206));
// regionPolygon.add(new Coord(49.05806402949591, 9.433248496152215)); // regionPolygon.add(new Coord(49.05806402949591, 9.433248496152215));
// regionPolygon.add(new Coord(49.05748752183746, 9.434353566266353)); // regionPolygon.add(new Coord(49.05748752183746, 9.434353566266353));
// regionPolygon.add(new Coord(49.05788826567445, 9.435544467068967)); // regionPolygon.add(new Coord(49.05788826567445, 9.435544467068967));
// regionPolygon.add(new Coord(49.06072150273306, 9.435233330823237)); // regionPolygon.add(new Coord(49.06072150273306, 9.435233330823237));
// regionPolygon.add(new Coord(49.06133312328379, 9.43515822897082)); // regionPolygon.add(new Coord(49.06133312328379, 9.43515822897082));
// regionPolygon.add(new Coord(49.06143154427858, 9.43440721044665)); // regionPolygon.add(new Coord(49.06143154427858, 9.43440721044665));
// regionPolygon.add(new Coord(49.06020829807264, 9.432239985562616)); // regionPolygon.add(new Coord(49.06020829807264, 9.432239985562616));
// //
// description.setRegionPolygon(regionPolygon); // description.setRegionPolygon(regionPolygon);
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);
job = new AsyncExportJob(description, new HTTPConnection("193.196.136.164")); job = new AsyncExportJob(description, new HTTPConnection("193.196.136.164"));
job.addJobStatusListener(this); job.addJobStatusListener(this);
try { try {
job.send(); job.send();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
ex.printStackTrace(); ex.printStackTrace();
} catch (InvalidJobDescriptorException ex) { } catch (InvalidJobDescriptorException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
// Wait for timeout, failure or that all tests pass // Wait for timeout, failure or that all tests pass
long timeout = 1000 * 60 * 3l; // 3 minutes maximum long timeout = 1000 * 60 * 3l; // 3 minutes maximum
long interval = 10000l; long interval = 10000l;
while (!job.hasFinished() && !job.hasFailed() && timeout > 0) { while (!job.hasFinished() && !job.hasFailed() && timeout > 0) {
Thread.sleep(interval); Thread.sleep(interval);
timeout -= interval; timeout -= interval;
System.out.println("+"); System.out.println("+");
} }
} }
@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.LOCAL) { if (status == JobStatus.LOCAL) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.SENT) { } else if (status == JobStatus.SENT) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.PENDING) { } else if (status == JobStatus.PENDING) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.RUNNING) { } else if (status == JobStatus.RUNNING) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.FINISHED) { } else if (status == JobStatus.FINISHED) {
try { try {
assertTrue(true); assertTrue(true);
job.downloadResult(); job.downloadResult();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
} else if (status == JobStatus.DOWNLOAD) { } else if (status == JobStatus.DOWNLOAD) {
try { try {
File file = job.getResult(); File file = job.getResult();
assertTrue(file.canRead()); assertTrue(file.canRead());
testForExistingLOD2AndMissingLOD1(file); testForExistingLOD2AndMissingLOD1(file);
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
} }
/** /**
* These asserts ensure that only LOD2 has been loaded as specified in the job descriptor above. * These asserts ensure that only LOD2 has been loaded as specified in the job descriptor above.
*/ */
private void testForExistingLOD2AndMissingLOD1(File file) { private void testForExistingLOD2AndMissingLOD1(File file) {
FileInputStream fileStream; FileInputStream fileStream;
try { try {
fileStream = new FileInputStream(file); fileStream = new FileInputStream(file);
ZipInputStream unzipStream = new ZipInputStream(fileStream); ZipInputStream unzipStream = new ZipInputStream(fileStream);
unzipStream.getNextEntry(); // Skip the first entry, its the job description unzipStream.getNextEntry(); // Skip the first entry, its the job description
unzipStream.getNextEntry(); unzipStream.getNextEntry();
File handle = Files.createTempDirectory("nfDownload").resolve("test.gml").toFile(); File handle = Files.createTempDirectory("nfDownload").resolve("test.gml").toFile();
BufferedOutputStream bos = BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(handle)); new BufferedOutputStream(new FileOutputStream(handle));
byte[] in = new byte[4096]; byte[] in = new byte[4096];
int read = 0; int read = 0;
while ((read = unzipStream.read(in)) != -1) { while ((read = unzipStream.read(in)) != -1) {
bos.write(in, 0, read); bos.write(in, 0, read);
} }
unzipStream.closeEntry(); unzipStream.closeEntry();
bos.close(); bos.close();
unzipStream.close(); unzipStream.close();
Scanner scanner = new Scanner(handle); Scanner scanner = new Scanner(handle);
boolean lod1Missing = true; boolean lod1Missing = true;
boolean lod2Found = false; boolean lod2Found = false;
while (scanner.hasNextLine()) { while (scanner.hasNextLine()) {
String line = scanner.nextLine(); String line = scanner.nextLine();
if (line.contains("lod2")) { if (line.contains("lod2")) {
lod2Found = true; lod2Found = true;
} }
if (line.contains("lod1")) { if (line.contains("lod1")) {
lod1Missing = false; lod1Missing = false;
} }
} }
scanner.close(); scanner.close();
assertTrue(lod1Missing); assertTrue(lod1Missing);
assertTrue(lod2Found); assertTrue(lod2Found);
} catch (IOException ex) { } catch (IOException ex) {
fail(); fail();
} }
} }
} }
\ No newline at end of file
package eu.simstadt.nf4j.async; package eu.simstadt.nf4j.async;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import org.junit.Test; import org.junit.Test;
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.AsyncImportJob; import eu.simstadt.nf4j.async.AsyncImportJob;
import eu.simstadt.nf4j.async.HTTPConnection; import eu.simstadt.nf4j.async.HTTPConnection;
import eu.simstadt.nf4j.async.ImportJobDescription; import eu.simstadt.nf4j.async.ImportJobDescription;
import eu.simstadt.nf4j.async.JobStatusEvent; import eu.simstadt.nf4j.async.JobStatusEvent;
import eu.simstadt.nf4j.async.JobStatusListener; import eu.simstadt.nf4j.async.JobStatusListener;
/** /**
* This class contains client oriented import job tests. It will send an import job and listens to * 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 * status updates. Every of the subsequent status' LOCAL, SENT, PENDING, RUNNING, FINISHED
* have to be signaled to this test class. * have to be signaled to this test class.
* *
* @author Marcel Bruse * @author Marcel Bruse
*/ */
public class SuccessfulImportJob implements JobStatusListener { public class SuccessfulImportJob implements JobStatusListener {
public AsyncImportJob job; public AsyncImportJob job;
@Test @Test
public void processJob() throws InterruptedException { public void processJob() throws InterruptedException {
ImportJobDescription desc = ImportJobDescription.getDefaultDescriptor(); ImportJobDescription desc = ImportJobDescription.getDefaultDescriptor();
desc.setProduct("LBTEST"); desc.setProduct("LBTEST");
desc.setLeaf("GR"); desc.setLeaf("GR");
desc.setCityGMLFile(new File("SomeBuildings.gml")); desc.setCityGMLFile(new File("SomeBuildings.gml"));
HTTPConnection connector = new HTTPConnection("193.196.136.164"); HTTPConnection connector = new HTTPConnection("193.196.136.164");
job = new AsyncImportJob(desc, connector); job = new AsyncImportJob(desc, connector);
job.addJobStatusListener(this); job.addJobStatusListener(this);
try { try {
job.send(); job.send();
} catch (InvalidJobDescriptorException ex) { } catch (InvalidJobDescriptorException ex) {
ex.printStackTrace(); ex.printStackTrace();
} catch (FailedTransmissionException ex) { } catch (FailedTransmissionException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
// Wait for timeout, failure or that all tests pass // Wait for timeout, failure or that all tests pass
long timeout = 1000 * 60 * 5l; // 5 minutes maximum long timeout = 1000 * 60 * 5l; // 5 minutes maximum
long interval = 10000l; long interval = 10000l;
while (!job.hasFinished() && !job.hasFailed() && timeout > 0) { while (!job.hasFinished() && !job.hasFailed() && timeout > 0) {
Thread.sleep(interval); Thread.sleep(interval);
timeout -= interval; timeout -= interval;
} }
} }
@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.LOCAL) { if (status == JobStatus.LOCAL) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.SENT) { } else if (status == JobStatus.SENT) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.PENDING) { } else if (status == JobStatus.PENDING) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.RUNNING) { } else if (status == JobStatus.RUNNING) {
assertTrue(true); assertTrue(true);
} else if (status == JobStatus.FINISHED) { } else if (status == JobStatus.FINISHED) {
assertTrue(true); assertTrue(true);
} }
} }
} }
\ No newline at end of file
Supports Markdown
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