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