Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
671c277b
Commit
671c277b
authored
4 months ago
by
Riegel
Browse files
Options
Download
Email Patches
Plain Diff
Style: Reformat code
parent
491b8247
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java
+658
-652
...va/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java
+13
-12
...a/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java
+18
-19
...ava/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java
CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java
+10
-7
...c/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java
+778
-781
...main/java/de/hft/stuttgart/citydoctor2/check/Checker.java
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java
+87
-90
.../java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java
with
1564 additions
and
1561 deletions
+1564
-1561
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/parser/CityGmlParser.java
+
658
-
652
View file @
671c277b
/*-
* Copyright 2022 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
...
...
@@ -18,28 +18,16 @@
*/
package
de.hft.stuttgart.citydoctor2.parser
;
import
java.io.*
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
javax.xml.XMLConstants
;
import
javax.xml.namespace.QName
;
import
javax.xml.parsers.ParserConfigurationException
;
import
javax.xml.parsers.SAXParser
;
import
javax.xml.parsers.SAXParserFactory
;
import
javax.xml.transform.Source
;
import
javax.xml.transform.stream.StreamSource
;
import
javax.xml.validation.Schema
;
import
javax.xml.validation.SchemaFactory
;
import
javax.xml.validation.Validator
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityObject
;
import
de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper
;
import
de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.utils.Localization
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile
;
import
de.hft.stuttgart.quality.QualityADEContext
;
import
de.hft.stuttgart.quality.QualityADEModule
;
import
org.apache.logging.log4j.Level
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
...
...
@@ -69,605 +57,623 @@ import org.locationtech.proj4j.CoordinateReferenceSystem;
import
org.locationtech.proj4j.ProjCoordinate
;
import
org.locationtech.proj4j.proj.Projection
;
import
org.locationtech.proj4j.units.Units
;
import
org.xml.sax.*
;
import
org.xml.sax.InputSource
;
import
org.xml.sax.SAXException
;
import
org.xml.sax.SAXNotRecognizedException
;
import
org.xml.sax.SAXNotSupportedException
;
import
org.xml.sax.SAXParseException
;
import
org.xmlobjects.schema.SchemaHandler
;
import
org.xmlobjects.schema.SchemaHandlerException
;
import
org.xmlobjects.stream.XMLReader
;
import
org.xmlobjects.stream.XMLReaderFactory
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityObject
;
import
de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper
;
import
de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.utils.Localization
;
import
de.hft.stuttgart.quality.QualityADEContext
;
import
de.hft.stuttgart.quality.QualityADEModule
;
import
javax.xml.XMLConstants
;
import
javax.xml.namespace.QName
;
import
javax.xml.parsers.ParserConfigurationException
;
import
javax.xml.parsers.SAXParser
;
import
javax.xml.parsers.SAXParserFactory
;
import
javax.xml.transform.Source
;
import
javax.xml.transform.stream.StreamSource
;
import
javax.xml.validation.Schema
;
import
javax.xml.validation.SchemaFactory
;
import
javax.xml.validation.Validator
;
import
java.io.BufferedInputStream
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Utility class to parse CityGML files.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public
class
CityGmlParser
{
private
static
final
String
CITY_OBJECT_MEMBER
=
"cityObjectMember"
;
private
static
final
String
WGS_84
=
"EPSG:4326"
;
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
CityGmlParser
.
class
);
private
static
final
CRSFactory
CRS_FACTORY
=
new
CRSFactory
();
// EPSG:31467
private
static
final
Pattern
P_EPSG
=
Pattern
.
compile
(
"^(EPSG:\\d+)$"
);
// urn:ogc:def:crs,crs:EPSG:6.12:31467,crs:EPSG:6.12:5783
// or
// urn:ogc:def:crs,crs:EPSG::28992
private
static
final
Pattern
P_OGC
=
Pattern
.
compile
(
"urn:ogc:def:crs,crs:EPSG:[\\d\\.]*:([\\d]+)\\D*"
);
private
static
final
Pattern
P_OGC2
=
Pattern
.
compile
(
"urn:ogc:def:crs:EPSG:[\\d\\.]*:([\\d]+)\\D*"
);
// urn:adv:crs:DE_DHDN_3GK3*DE_DHHN92_NH
// urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH
private
static
final
Pattern
P_URN
=
Pattern
.
compile
(
"urn:adv:crs:([^\\*]+)"
);
private
static
final
SAXParserFactory
FACTORY
;
private
static
CityGMLContext
context
;
private
static
List
<
QName
>
chunkProperties
=
new
ArrayList
<>();
static
{
System
.
setProperty
(
"javax.xml.transform.TransformerFactory"
,
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"
);
FACTORY
=
SAXParserFactory
.
newInstance
();
try
{
FACTORY
.
setFeature
(
XMLConstants
.
FEATURE_SECURE_PROCESSING
,
false
);
}
catch
(
SAXNotRecognizedException
|
SAXNotSupportedException
|
ParserConfigurationException
e
)
{
logger
.
catching
(
e
);
}
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_1_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_2_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_3_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
}
private
CityGmlParser
()
{
}
public
static
synchronized
CityGMLContext
getContext
()
{
if
(
context
==
null
)
{
try
{
context
=
CityGMLContext
.
newInstance
(
CityGmlParser
.
class
.
getClassLoader
());
// also setup ades
ADERegistry
adeRegistry
=
ADERegistry
.
getInstance
();
adeRegistry
.
loadADE
(
new
QualityADEContext
());
}
catch
(
CityGMLContextException
e
)
{
logger
.
fatal
(
"Unable to create citygml4j context"
,
e
);
throw
new
IllegalStateException
(
"Unable to create citygml4j context"
);
}
catch
(
ADEException
e
)
{
logger
.
fatal
(
"Unable to add ADE plugins to citygml4j"
,
e
);
throw
new
IllegalStateException
(
"Unable to add ADE plugins to citygml4j"
);
}
}
return
context
;
}
public
static
CityDoctorModel
parseCityGmlFileSilently
(
String
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
null
,
null
,
false
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
null
,
null
,
true
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
file
,
ParserConfiguration
config
,
ProgressListener
l
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
l
,
null
,
true
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
filePath
,
ParserConfiguration
config
,
ProgressListener
l
,
GMLValidationHandler
handler
,
boolean
verbose
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
CityGMLContext
context
=
getContext
();
Path
file
=
Paths
.
get
(
filePath
);
if
(
config
.
getValidate
())
{
List
<
String
>
messages
=
validateFile
(
context
,
handler
,
file
);
if
(!
messages
.
isEmpty
())
{
throw
new
InvalidGmlFileException
(
"Invalid GML File. First error: \n"
+
messages
.
get
(
0
));
}
}
try
{
parseEpsgCodeFromFile
(
file
,
config
);
CityGMLInputFactory
in
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
file
.
toFile
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
return
readAndKeepFeatures
(
config
,
file
,
in
,
ois
,
verbose
);
}
}
catch
(
CityGMLReadException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
public
static
CityDoctorModel
parseCityGmlZipEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
)
private
static
final
String
CITY_OBJECT_MEMBER
=
"cityObjectMember"
;
private
static
final
String
WGS_84
=
"EPSG:4326"
;
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
CityGmlParser
.
class
);
private
static
final
CRSFactory
CRS_FACTORY
=
new
CRSFactory
();
// EPSG:31467
private
static
final
Pattern
P_EPSG
=
Pattern
.
compile
(
"^(EPSG:\\d+)$"
);
// urn:ogc:def:crs,crs:EPSG:6.12:31467,crs:EPSG:6.12:5783
// or
// urn:ogc:def:crs,crs:EPSG::28992
private
static
final
Pattern
P_OGC
=
Pattern
.
compile
(
"urn:ogc:def:crs,crs:EPSG:[\\d\\.]*:([\\d]+)\\D*"
);
private
static
final
Pattern
P_OGC2
=
Pattern
.
compile
(
"urn:ogc:def:crs:EPSG:[\\d\\.]*:([\\d]+)\\D*"
);
// urn:adv:crs:DE_DHDN_3GK3*DE_DHHN92_NH
// urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH
private
static
final
Pattern
P_URN
=
Pattern
.
compile
(
"urn:adv:crs:([^\\*]+)"
);
private
static
final
SAXParserFactory
FACTORY
;
private
static
CityGMLContext
context
;
private
static
List
<
QName
>
chunkProperties
=
new
ArrayList
<>();
static
{
System
.
setProperty
(
"javax.xml.transform.TransformerFactory"
,
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"
);
FACTORY
=
SAXParserFactory
.
newInstance
();
try
{
FACTORY
.
setFeature
(
XMLConstants
.
FEATURE_SECURE_PROCESSING
,
false
);
}
catch
(
SAXNotRecognizedException
|
SAXNotSupportedException
|
ParserConfigurationException
e
)
{
logger
.
catching
(
e
);
}
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_1_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_2_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
chunkProperties
.
add
(
new
QName
(
CityGMLConstants
.
CITYGML_3_0_CORE_NAMESPACE
,
CITY_OBJECT_MEMBER
));
}
private
CityGmlParser
()
{
}
public
static
synchronized
CityGMLContext
getContext
()
{
if
(
context
==
null
)
{
try
{
context
=
CityGMLContext
.
newInstance
(
CityGmlParser
.
class
.
getClassLoader
());
// also setup ades
ADERegistry
adeRegistry
=
ADERegistry
.
getInstance
();
adeRegistry
.
loadADE
(
new
QualityADEContext
());
}
catch
(
CityGMLContextException
e
)
{
logger
.
fatal
(
"Unable to create citygml4j context"
,
e
);
throw
new
IllegalStateException
(
"Unable to create citygml4j context"
);
}
catch
(
ADEException
e
)
{
logger
.
fatal
(
"Unable to add ADE plugins to citygml4j"
,
e
);
throw
new
IllegalStateException
(
"Unable to add ADE plugins to citygml4j"
);
}
}
return
context
;
}
public
static
CityDoctorModel
parseCityGmlFileSilently
(
String
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
null
,
null
,
false
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
null
,
null
,
true
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
file
,
ParserConfiguration
config
,
ProgressListener
l
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
return
parseCityGmlFile
(
file
,
config
,
l
,
null
,
true
);
}
public
static
CityDoctorModel
parseCityGmlFile
(
String
filePath
,
ParserConfiguration
config
,
ProgressListener
l
,
GMLValidationHandler
handler
,
boolean
verbose
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
CityGMLContext
context
=
getContext
();
Path
file
=
Paths
.
get
(
filePath
);
if
(
config
.
getValidate
())
{
List
<
String
>
messages
=
validateFile
(
context
,
handler
,
file
);
if
(!
messages
.
isEmpty
())
{
throw
new
InvalidGmlFileException
(
"Invalid GML File. First error: \n"
+
messages
.
get
(
0
));
}
}
try
{
parseEpsgCodeFromFile
(
file
,
config
);
CityGMLInputFactory
in
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
file
.
toFile
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
return
readAndKeepFeatures
(
config
,
file
,
in
,
ois
,
verbose
);
}
}
catch
(
CityGMLReadException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
public
static
CityDoctorModel
parseCityGmlZipEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
)
throws
CityGmlParseException
,
InvalidGmlFileException
,
IOException
{
CityGMLContext
context
=
getContext
();
if
(
config
.
getValidate
())
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
)){
List
<
String
>
messages
=
validateStream
(
entryFile
.
getInputStream
(),
context
);
if
(!
messages
.
isEmpty
())
{
throw
new
InvalidGmlFileException
(
"Invalid GML File. First error: \n"
+
messages
.
get
(
0
));
}
}
catch
(
Exception
e
)
{
CityGMLContext
context
=
getContext
();
if
(
config
.
getValidate
())
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
List
<
String
>
messages
=
validateStream
(
entryFile
.
getInputStream
(),
context
);
if
(!
messages
.
isEmpty
())
{
throw
new
InvalidGmlFileException
(
"Invalid GML File. First error: \n"
+
messages
.
get
(
0
));
}
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
e
);
}
}
return
decompressAndParseCityGmlEntry
(
entry
,
config
,
context
);
}
public
static
CityDoctorModel
decompressAndParseCityGmlEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
CityGMLContext
context
)
throws
CityGmlParseException
{
return
decompressAndParseCityGmlEntry
(
entry
,
config
,
null
,
context
);
}
public
static
CityDoctorModel
decompressAndParseCityGmlEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGMLContext
context
)
throws
CityGmlParseException
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
)){
BufferedInputStream
bis
=
new
BufferedInputStream
(
entryFile
.
getInputStream
());
readEpsgCodeFromInputStream
(
bis
,
config
);
CityGMLInputFactory
in
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
bis
,
bis
.
available
())){
if
(
l
!=
null
){
ois
.
addListener
(
l:
:
updateProgress
);
}
return
readAndKeepFeatures
(
config
,
entry
,
in
,
ois
,
false
);
}
}
catch
(
CityGMLReadException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
catch
(
Exception
e
)
{
return
decompressAndParseCityGmlEntry
(
entry
,
config
,
context
);
}
public
static
CityDoctorModel
decompressAndParseCityGmlEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
CityGMLContext
context
)
throws
CityGmlParseException
{
return
decompressAndParseCityGmlEntry
(
entry
,
config
,
null
,
context
);
}
public
static
CityDoctorModel
decompressAndParseCityGmlEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGMLContext
context
)
throws
CityGmlParseException
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
BufferedInputStream
bis
=
new
BufferedInputStream
(
entryFile
.
getInputStream
());
readEpsgCodeFromInputStream
(
bis
,
config
);
CityGMLInputFactory
in
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
bis
,
bis
.
available
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
return
readAndKeepFeatures
(
config
,
entry
,
in
,
ois
,
false
);
}
}
catch
(
CityGMLReadException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
e
);
}
}
private
static
CityDoctorModel
readAndKeepFeatures
(
ParserConfiguration
config
,
CityGmlZipEntry
entry
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
return
readAndKeepModel
(
new
Citygml3FeatureMapper
(
config
,
entry
),
inputFactory
,
ois
,
verbose
);
}
private
static
List
<
String
>
validateStream
(
InputStream
vis
,
CityGMLContext
context
)
throws
CityGmlParseException
{
GMLValidationHandler
handler
=
new
GMLValidationHandler
();
try
{
BufferedInputStream
bis
=
new
BufferedInputStream
(
vis
);
SchemaHandler
schemaHandler
=
new
ValidationSchemaHandler
(
context
.
getDefaultSchemaHandler
());
readAdditionalSchemaDefinitions
(
context
,
bis
,
schemaHandler
);
Source
[]
schemas
=
schemaHandler
.
getSchemas
();
SchemaFactory
schemaFactory
=
SchemaFactory
.
newInstance
(
XMLConstants
.
W3C_XML_SCHEMA_NS_URI
);
schemaFactory
.
setFeature
(
"http://apache.org/xml/features/disallow-doctype-decl"
,
true
);
Schema
schema
=
schemaFactory
.
newSchema
(
schemas
);
Validator
validator
=
schema
.
newValidator
();
validator
.
setErrorHandler
(
handler
);
validator
.
validate
(
new
StreamSource
(
bis
));
return
handler
.
getMessages
();
}
catch
(
SchemaHandlerException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to validate CityGML file"
,
e
);
}
}
private
static
void
readAdditionalSchemaDefinitions
(
CityGMLContext
context
,
BufferedInputStream
bis
,
SchemaHandler
schemaHandler
)
throws
CityGmlParseException
{
bis
.
mark
(
Integer
.
MAX_VALUE
);
try
(
XMLReader
reader
=
XMLReaderFactory
.
newInstance
(
context
.
getXMLObjects
())
.
withSchemaHandler
(
schemaHandler
)
.
createReader
(
bis
))
{
reader
.
nextTag
();
bis
.
reset
();
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
"Failed to read Schema from stream."
,
e
);
}
}
private
static
void
readEpsgCodeFromInputStream
(
BufferedInputStream
bis
,
ParserConfiguration
config
)
throws
CityGmlParseException
{
try
{
// Mark start position of GML-"file"
bis
.
mark
(
Integer
.
MAX_VALUE
);
// Buffer the first 10000 chars of the Stream, EPSG/envelope info should be found within that range
int
peekingWidth
=
Math
.
min
(
10000
,
bis
.
available
());
byte
[]
buf
=
new
byte
[
peekingWidth
];
bis
.
read
(
buf
,
0
,
peekingWidth
);
bis
.
reset
();
parseEpsgCodeFromBuffer
(
buf
,
config
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
public
static
void
streamCityGml
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
,
IOException
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
parseEpsgCodeFromStream
(
entryFile
.
getInputStream
(),
config
);
startReadingCityGmlZipEntry
(
entry
,
config
,
null
,
cityObjectConsumer
,
outputFile
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML stream"
,
e
);
}
}
public
static
void
streamCityGml
(
String
file
,
ParserConfiguration
config
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
Path
f
=
Paths
.
get
(
file
);
streamCityGml
(
f
,
config
,
null
,
cityObjectConsumer
,
outputFile
);
}
public
static
void
streamCityGml
(
File
file
,
ParserConfiguration
parserConfig
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
streamCityGml
(
file
.
toPath
(),
parserConfig
,
null
,
cityObjectConsumer
,
outputFile
);
}
public
static
void
streamCityGml
(
Path
file
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
parseEpsgCodeFromFile
(
file
,
config
);
startReadingCityGmlFile
(
file
,
config
,
l
,
cityObjectConsumer
,
outputFile
);
}
public
static
CityModel
parseOnlyCityModel
(
File
inputFile
)
throws
CityGmlParseException
{
try
{
CityGMLInputFactory
inputFactory
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
inputFile
))
{
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
return
cModel
;
}
}
}
}
catch
(
CityGMLReadException
e
)
{
throw
new
CityGmlParseException
(
e
);
}
throw
new
CityGmlParseException
(
"Did not find any CityModel in CityGML file"
);
}
private
static
CityDoctorModel
readAndKeepFeatures
(
ParserConfiguration
config
,
CityGmlZipEntry
entry
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
return
readAndKeepModel
(
new
Citygml3FeatureMapper
(
config
,
entry
),
inputFactory
,
ois
,
verbose
);
}
private
static
List
<
String
>
validateStream
(
InputStream
vis
,
CityGMLContext
context
)
throws
CityGmlParseException
{
GMLValidationHandler
handler
=
new
GMLValidationHandler
();
try
{
BufferedInputStream
bis
=
new
BufferedInputStream
(
vis
);
SchemaHandler
schemaHandler
=
new
ValidationSchemaHandler
(
context
.
getDefaultSchemaHandler
());
readAdditionalSchemaDefinitions
(
context
,
bis
,
schemaHandler
);
Source
[]
schemas
=
schemaHandler
.
getSchemas
();
SchemaFactory
schemaFactory
=
SchemaFactory
.
newInstance
(
XMLConstants
.
W3C_XML_SCHEMA_NS_URI
);
schemaFactory
.
setFeature
(
"http://apache.org/xml/features/disallow-doctype-decl"
,
true
);
Schema
schema
=
schemaFactory
.
newSchema
(
schemas
);
Validator
validator
=
schema
.
newValidator
();
validator
.
setErrorHandler
(
handler
);
validator
.
validate
(
new
StreamSource
(
bis
));
return
handler
.
getMessages
();
}
catch
(
SchemaHandlerException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to validate CityGML file"
,
e
);
}
}
private
static
void
readAdditionalSchemaDefinitions
(
CityGMLContext
context
,
BufferedInputStream
bis
,
SchemaHandler
schemaHandler
)
throws
CityGmlParseException
{
bis
.
mark
(
Integer
.
MAX_VALUE
);
try
(
XMLReader
reader
=
XMLReaderFactory
.
newInstance
(
context
.
getXMLObjects
())
.
withSchemaHandler
(
schemaHandler
)
.
createReader
(
bis
))
{
reader
.
nextTag
();
bis
.
reset
();
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
"Failed to read Schema from stream."
,
e
);
}
}
private
static
void
readEpsgCodeFromInputStream
(
BufferedInputStream
bis
,
ParserConfiguration
config
)
throws
CityGmlParseException
{
try
{
// Mark start position of GML-"file"
bis
.
mark
(
Integer
.
MAX_VALUE
);
// Buffer the first 10000 chars of the Stream, EPSG/envelope info should be found within that range
int
peekingWidth
=
Math
.
min
(
10000
,
bis
.
available
());
byte
[]
buf
=
new
byte
[
peekingWidth
];
bis
.
read
(
buf
,
0
,
peekingWidth
);
bis
.
reset
();
parseEpsgCodeFromBuffer
(
buf
,
config
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
public
static
void
streamCityGml
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
,
IOException
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
parseEpsgCodeFromStream
(
entryFile
.
getInputStream
(),
config
);
startReadingCityGmlZipEntry
(
entry
,
config
,
null
,
cityObjectConsumer
,
outputFile
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML stream"
,
e
);
}
}
public
static
void
streamCityGml
(
String
file
,
ParserConfiguration
config
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
Path
f
=
Paths
.
get
(
file
);
streamCityGml
(
f
,
config
,
null
,
cityObjectConsumer
,
outputFile
);
}
public
static
void
streamCityGml
(
File
file
,
ParserConfiguration
parserConfig
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
streamCityGml
(
file
.
toPath
(),
parserConfig
,
null
,
cityObjectConsumer
,
outputFile
);
}
public
static
void
streamCityGml
(
Path
file
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGmlParseException
{
parseEpsgCodeFromFile
(
file
,
config
);
startReadingCityGmlFile
(
file
,
config
,
l
,
cityObjectConsumer
,
outputFile
);
}
public
static
CityModel
parseOnlyCityModel
(
File
inputFile
)
throws
CityGmlParseException
{
try
{
CityGMLInputFactory
inputFactory
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
inputFile
))
{
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
return
cModel
;
}
}
}
}
catch
(
CityGMLReadException
e
)
{
throw
new
CityGmlParseException
(
e
);
}
throw
new
CityGmlParseException
(
"Did not find any CityModel in CityGML file"
);
}
private
static
void
startReadingCityGmlFile
(
Path
file
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
{
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
file
.
toFile
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
readAndDiscardFeatures
(
file
,
config
,
ois
,
cityObjectConsumer
,
outputFile
);
}
catch
(
IOException
|
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
());
logger
.
catching
(
Level
.
ERROR
,
e
);
}
}
private
static
void
readAndDiscardFeatures
(
Path
file
,
ParserConfiguration
config
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
Citygml3FeatureMapper
mapper
=
new
Citygml3FeatureMapper
(
config
,
file
);
readAndDiscardModel
(
mapper
,
ois
,
cityObjectConsumer
,
outputFile
);
}
private
static
void
startReadingCityGmlZipEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
);
ObservedInputStream
ois
=
new
ObservedInputStream
(
entryFile
.
getInputStream
(),
entry
.
getFileSize
())){
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
streamAndDiscardFeatures
(
entry
,
config
,
ois
,
cityObjectConsumer
,
outputFile
);
}
catch
(
IOException
|
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
());
logger
.
catching
(
Level
.
ERROR
,
e
);
}
}
private
static
void
streamAndDiscardFeatures
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
Citygml3FeatureMapper
mapper
=
new
Citygml3FeatureMapper
(
config
,
entry
);
readAndDiscardModel
(
mapper
,
ois
,
cityObjectConsumer
,
outputFile
);
}
private
static
void
readAndDiscardModel
(
Citygml3FeatureMapper
mapper
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
getContext
();
CityGMLInputFactory
inputFactory
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
CityGMLChunkWriter
writer
=
null
;
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
ois
))
{
CityDoctorModel
model
=
mapper
.
getModel
();
boolean
isInitialized
=
false
;
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
if
(
writer
==
null
)
{
writer
=
createCityModelWriter
(
outputFile
,
reader
);
}
if
(!
isInitialized
&&
writer
!=
null
&&
reader
.
getParentInfo
()
!=
null
&&
reader
.
getParentInfo
().
getTypeName
().
getLocalPart
().
equals
(
"CityModel"
))
{
FeatureInfo
parentInfo
=
reader
.
getParentInfo
();
writer
.
withCityModelInfo
(
parentInfo
);
isInitialized
=
true
;
}
if
(
chunk
instanceof
AbstractCityObject
ag
)
{
ag
.
accept
(
mapper
);
drainCityModel
(
model
,
cityObjectConsumer
);
writeAbstractCityObject
(
writer
,
ag
);
}
else
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
mapper
.
setCityModel
(
cModel
);
cityObjectConsumer
.
accept
(
cModel
);
writeCityModel
(
writer
,
cModel
);
}
else
if
(
writer
!=
null
)
{
writer
.
writeMember
(
chunk
);
}
}
// end of stream
logger
.
debug
(
"End of gml file stream"
);
}
catch
(
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
(),
e
);
}
catch
(
CityGMLWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorWritingGmlFile"
),
e
.
getMessage
(),
e
);
}
finally
{
if
(
writer
!=
null
)
{
try
{
writer
.
close
();
}
catch
(
CityGMLWriteException
e
)
{
// ignore
}
}
}
}
private
static
void
writeCityModel
(
CityGMLChunkWriter
writer
,
CityModel
cModel
)
{
if
(
writer
!=
null
)
{
for
(
ADEProperty
genEle
:
cModel
.
getADEProperties
())
{
writer
.
getCityModelInfo
().
addADEProperty
(
genEle
);
}
}
}
private
static
void
writeAbstractCityObject
(
CityGMLChunkWriter
writer
,
AbstractCityObject
ag
)
throws
CityGMLWriteException
{
if
(
writer
!=
null
)
{
writer
.
writeMember
(
ag
);
}
}
private
static
CityGMLChunkWriter
createCityModelWriter
(
String
outputFile
,
CityGMLReader
reader
)
throws
CityGMLWriteException
{
if
(
outputFile
==
null
)
{
return
null
;
}
CityGMLContext
gmlContext
=
CityGmlParser
.
getContext
();
CityGMLVersion
version
=
CityGMLModules
.
getCityGMLVersion
(
reader
.
getName
().
getNamespaceURI
());
CityGMLOutputFactory
factory
=
gmlContext
.
createCityGMLOutputFactory
(
version
);
CityGMLChunkWriter
writer
=
factory
.
createCityGMLChunkWriter
(
new
File
(
outputFile
),
StandardCharsets
.
UTF_8
.
name
());
writer
.
withPrefix
(
"qual"
,
QualityADEModule
.
NAMESPACE_URI
);
writer
.
withSchemaLocation
(
QualityADEModule
.
NAMESPACE_URI
,
QualityADEModule
.
NAMESPACE_URI
+
"/qualityAde.xsd"
);
writer
.
withIndent
(
" "
);
writer
.
withDefaultPrefixes
();
writer
.
withDefaultSchemaLocations
();
return
writer
;
}
private
static
CityDoctorModel
readAndKeepFeatures
(
ParserConfiguration
config
,
Path
file
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
return
readAndKeepModel
(
new
Citygml3FeatureMapper
(
config
,
file
),
inputFactory
,
ois
,
verbose
);
}
private
static
CityDoctorModel
readAndKeepModel
(
Citygml3FeatureMapper
mapper
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
ois
))
{
CityGMLVersion
version
=
null
;
// model is read in chunked mode
// object members are replaced by href in model
// need to remove the refs and re-add unparsed objects
List
<
AbstractCityObject
>
acos
=
new
ArrayList
<>();
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
version
=
CityGMLModules
.
getCityGMLVersion
(
reader
.
getName
().
getNamespaceURI
());
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
mapper
.
setCityModel
(
cModel
);
mapper
.
setCityGMLVersion
(
version
);
}
else
if
(
chunk
instanceof
AbstractCityObject
aco
)
{
acos
.
add
(
aco
);
aco
.
accept
(
mapper
);
}
}
if
(
mapper
.
getModel
().
getCityModel
()
==
null
)
{
// file does not contain a city model?
// create it for now
mapper
.
setCityModel
(
new
CityModel
());
}
CityModel
cModel
=
mapper
.
getModel
().
getCityModel
();
// remove those that should have been parsed
List
<
AbstractCityObject
>
parsedCityObjects
=
mapper
.
getModel
().
createFeatureStream
()
.
map
(
CityObject:
:
getGmlObject
).
toList
();
acos
.
removeAll
(
parsedCityObjects
);
// re-add all not parsed objects
for
(
AbstractCityObject
aco
:
acos
)
{
cModel
.
getCityObjectMembers
().
add
(
new
AbstractCityObjectProperty
(
aco
));
}
if
(
logger
.
isInfoEnabled
()
&&
verbose
)
{
logger
.
info
(
Localization
.
getText
(
"CityGmlParser.parsedObjects"
),
mapper
.
getModel
().
getNumberOfFeatures
());
}
mapper
.
setCityGMLVersion
(
version
);
return
mapper
.
getModel
();
}
}
private
static
void
parseEpsgCodeFromFile
(
Path
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
{
try
(
BufferedInputStream
bis
=
new
BufferedInputStream
(
new
FileInputStream
(
file
.
toFile
())))
{
parseEpsgCodeFromStream
(
bis
,
config
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
private
static
void
parseEpsgCodeFromStream
(
InputStream
is
,
ParserConfiguration
config
)
throws
ParserConfigurationException
,
SAXException
{
SAXParser
parser
=
FACTORY
.
newSAXParser
();
CityGmlHandler
handler
=
new
CityGmlHandler
();
try
{
parser
.
parse
(
new
InputSource
(
is
),
handler
);
}
catch
(
EnvelopeFoundException
e
)
{
try
{
parseCoordinateSystem
(
config
,
handler
);
}
catch
(
Exception
e2
)
{
logEpsgParseError
(
e2
);
}
}
catch
(
Exception
e
)
{
logEpsgParseError
(
e
);
}
}
private
static
void
parseEpsgCodeFromBuffer
(
byte
[]
buffer
,
ParserConfiguration
config
)
throws
ParserConfigurationException
,
SAXException
{
InputStream
is
=
new
ByteArrayInputStream
(
buffer
);
SAXParser
parser
=
FACTORY
.
newSAXParser
();
CityGmlHandler
handler
=
new
CityGmlHandler
();
try
{
parser
.
parse
(
new
InputSource
(
is
),
handler
);
}
catch
(
EnvelopeFoundException
e
)
{
try
{
parseCoordinateSystem
(
config
,
handler
);
}
catch
(
Exception
e2
)
{
logEpsgParseError
(
e2
);
}
}
catch
(
SAXParseException
spe
){
// suppress XML document structure warning
if
(!
spe
.
getMessage
().
matches
(
"XML document structures must start and end within the same entity."
)){
logEpsgParseError
(
spe
);
}
}
catch
(
Exception
e
)
{
logEpsgParseError
(
e
);
}
}
private
static
void
logEpsgParseError
(
Exception
e
){
logger
.
debug
(
"Exception while parsing for EPSG code"
,
e
);
if
(
logger
.
isWarnEnabled
())
{
logger
.
warn
(
Localization
.
getText
(
"CityGmlParser.noEPSG"
));
}
}
private
static
void
parseCoordinateSystem
(
ParserConfiguration
config
,
CityGmlHandler
handler
)
{
if
(
handler
.
getEpsg
()
==
null
)
{
return
;
}
CoordinateReferenceSystem
crs
=
crsFromSrsName
(
handler
.
getEpsg
());
if
(
crs
==
null
)
{
// could not find a coordinate system for srsName
// assuming metric system
return
;
}
if
(
crs
.
getProjection
().
getUnits
()
==
Units
.
METRES
)
{
// coordinate system is in meters, do not convert
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"CityGmlParser.noConversionNeeded"
));
}
return
;
}
parseMeterConversion
(
config
,
crs
);
Vector3d
low
=
handler
.
getLowerCorner
();
Vector3d
up
=
handler
.
getUpperCorner
();
double
centerLong
=
low
.
getX
()
+
((
up
.
getX
()
-
low
.
getX
())
/
2
);
double
centerLat
=
low
.
getY
()
+
((
up
.
getY
()
-
low
.
getY
())
/
2
);
if
(!
crs
.
getName
().
equals
(
WGS_84
))
{
// need to convert coordinates first to WGS84, then find UTM Zone
CoordinateReferenceSystem
wgs84
=
crsFromSrsName
(
WGS_84
);
ProjCoordinate
p1
=
new
ProjCoordinate
();
p1
.
setValue
(
centerLong
,
centerLat
);
ProjCoordinate
p2
=
new
ProjCoordinate
();
BasicCoordinateTransform
bct
=
new
BasicCoordinateTransform
(
crs
,
wgs84
);
bct
.
transform
(
p1
,
p2
);
centerLong
=
p2
.
x
;
centerLat
=
p2
.
y
;
}
int
zone
=
(
int
)
(
31
+
Math
.
round
(
centerLong
/
6
));
CoordinateReferenceSystem
utm
;
if
(
centerLat
<
0
)
{
// south
logger
.
info
(
"Converting coordiante system to UTM zone {}S"
,
zone
);
utm
=
CRS_FACTORY
.
createFromParameters
(
"UTM"
,
"+proj=utm +ellps=WGS84 +units=m +zone="
+
zone
+
" +south"
);
}
else
{
// north
logger
.
info
(
"Converting coordiante system to UTM zone {}N"
,
zone
);
utm
=
CRS_FACTORY
.
createFromParameters
(
"UTM"
,
"+proj=utm +ellps=WGS84 +units=m +zone="
+
zone
);
}
config
.
setCoordinateSystem
(
crs
,
utm
);
}
private
static
void
parseMeterConversion
(
ParserConfiguration
config
,
CoordinateReferenceSystem
crs
)
{
Projection
projection
=
crs
.
getProjection
();
double
fromMetres
=
projection
.
getFromMetres
();
if
(
fromMetres
>
0
)
{
// also transform height information
config
.
setFromMeters
(
fromMetres
);
}
else
{
config
.
setFromMeters
(
1.0
);
}
}
/**
* The srsName (The name by which this reference system is identified) inside
* the CityGML file can have multiple formats. This method tries to parse the
* string and detect the corresponding reference system. If it is found, it
* returns a proj4j.CoordinateReferenceSystem. It throws an
* IllegalArgumentException otherwise.
*
* This method should be able to parse any EPSG id : e.g. "EPSG:1234". German
* Citygmls might also have "DE_DHDN_3GK3" or "ETRS89_UTM32" as srsName, so
* those are also included. It isn't guaranteed that those formats are correctly
* parsed, though.
*
* The EPSG ids and parameters are defined in resources ('nad/epsg') inside
* proj4j-0.1.0.jar. Some EPSG ids are missing though, e.g. 7415
*
* @param srsName
* @return CoordinateReferenceSystem
*/
private
static
CoordinateReferenceSystem
crsFromSrsName
(
String
srsName
)
{
srsName
=
srsName
.
trim
();
Matcher
mEPSG
=
P_EPSG
.
matcher
(
srsName
);
if
(
mEPSG
.
find
())
{
if
(
"EPSG:4979"
.
contentEquals
(
srsName
))
{
srsName
=
"EPSG:4236"
;
}
else
if
(
"EPSG:7415"
.
contentEquals
(
srsName
))
{
return
CRS_FACTORY
.
createFromParameters
(
"EPSG:7415"
,
"+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs"
);
}
return
CRS_FACTORY
.
createFromName
(
srsName
);
}
Matcher
mOGC
=
P_OGC
.
matcher
(
srsName
);
if
(
mOGC
.
find
())
{
return
CRS_FACTORY
.
createFromName
(
"EPSG:"
+
mOGC
.
group
(
1
));
}
Matcher
mOGC2
=
P_OGC2
.
matcher
(
srsName
);
if
(
mOGC2
.
find
())
{
return
CRS_FACTORY
.
createFromName
(
"EPSG:"
+
mOGC2
.
group
(
1
));
}
Matcher
mURN
=
P_URN
.
matcher
(
srsName
);
// NOTE: Could use a HashMap if the switch/case becomes too long.
if
(
mURN
.
find
())
{
private
static
void
startReadingCityGmlFile
(
Path
file
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
{
try
(
ObservedInputStream
ois
=
new
ObservedInputStream
(
file
.
toFile
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
readAndDiscardFeatures
(
file
,
config
,
ois
,
cityObjectConsumer
,
outputFile
);
}
catch
(
IOException
|
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
());
logger
.
catching
(
Level
.
ERROR
,
e
);
}
}
private
static
void
readAndDiscardFeatures
(
Path
file
,
ParserConfiguration
config
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
Citygml3FeatureMapper
mapper
=
new
Citygml3FeatureMapper
(
config
,
file
);
readAndDiscardModel
(
mapper
,
ois
,
cityObjectConsumer
,
outputFile
);
}
private
static
void
startReadingCityGmlZipEntry
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ProgressListener
l
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
);
ObservedInputStream
ois
=
new
ObservedInputStream
(
entryFile
.
getInputStream
(),
entry
.
getFileSize
()))
{
if
(
l
!=
null
)
{
ois
.
addListener
(
l:
:
updateProgress
);
}
streamAndDiscardFeatures
(
entry
,
config
,
ois
,
cityObjectConsumer
,
outputFile
);
}
catch
(
IOException
|
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
());
logger
.
catching
(
Level
.
ERROR
,
e
);
}
}
private
static
void
streamAndDiscardFeatures
(
CityGmlZipEntry
entry
,
ParserConfiguration
config
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
Citygml3FeatureMapper
mapper
=
new
Citygml3FeatureMapper
(
config
,
entry
);
readAndDiscardModel
(
mapper
,
ois
,
cityObjectConsumer
,
outputFile
);
}
private
static
void
readAndDiscardModel
(
Citygml3FeatureMapper
mapper
,
ObservedInputStream
ois
,
CityGmlConsumer
cityObjectConsumer
,
String
outputFile
)
throws
CityGMLReadException
{
getContext
();
CityGMLInputFactory
inputFactory
=
context
.
createCityGMLInputFactory
()
.
withChunking
(
ChunkOptions
.
chunkByProperties
(
chunkProperties
).
skipCityModel
(
false
));
CityGMLChunkWriter
writer
=
null
;
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
ois
))
{
CityDoctorModel
model
=
mapper
.
getModel
();
boolean
isInitialized
=
false
;
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
if
(
writer
==
null
)
{
writer
=
createCityModelWriter
(
outputFile
,
reader
);
}
if
(!
isInitialized
&&
writer
!=
null
&&
reader
.
getParentInfo
()
!=
null
&&
reader
.
getParentInfo
().
getTypeName
().
getLocalPart
().
equals
(
"CityModel"
))
{
FeatureInfo
parentInfo
=
reader
.
getParentInfo
();
writer
.
withCityModelInfo
(
parentInfo
);
isInitialized
=
true
;
}
if
(
chunk
instanceof
AbstractCityObject
ag
)
{
ag
.
accept
(
mapper
);
drainCityModel
(
model
,
cityObjectConsumer
);
writeAbstractCityObject
(
writer
,
ag
);
}
else
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
mapper
.
setCityModel
(
cModel
);
cityObjectConsumer
.
accept
(
cModel
);
writeCityModel
(
writer
,
cModel
);
}
else
if
(
writer
!=
null
)
{
writer
.
writeMember
(
chunk
);
}
}
// end of stream
logger
.
debug
(
"End of gml file stream"
);
}
catch
(
CityGMLReadException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorReadingGmlFile"
),
e
.
getMessage
(),
e
);
}
catch
(
CityGMLWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"CityGmlParser.errorWritingGmlFile"
),
e
.
getMessage
(),
e
);
}
finally
{
if
(
writer
!=
null
)
{
try
{
writer
.
close
();
}
catch
(
CityGMLWriteException
e
)
{
// ignore
}
}
}
}
private
static
void
writeCityModel
(
CityGMLChunkWriter
writer
,
CityModel
cModel
)
{
if
(
writer
!=
null
)
{
for
(
ADEProperty
genEle
:
cModel
.
getADEProperties
())
{
writer
.
getCityModelInfo
().
addADEProperty
(
genEle
);
}
}
}
private
static
void
writeAbstractCityObject
(
CityGMLChunkWriter
writer
,
AbstractCityObject
ag
)
throws
CityGMLWriteException
{
if
(
writer
!=
null
)
{
writer
.
writeMember
(
ag
);
}
}
private
static
CityGMLChunkWriter
createCityModelWriter
(
String
outputFile
,
CityGMLReader
reader
)
throws
CityGMLWriteException
{
if
(
outputFile
==
null
)
{
return
null
;
}
CityGMLContext
gmlContext
=
CityGmlParser
.
getContext
();
CityGMLVersion
version
=
CityGMLModules
.
getCityGMLVersion
(
reader
.
getName
().
getNamespaceURI
());
CityGMLOutputFactory
factory
=
gmlContext
.
createCityGMLOutputFactory
(
version
);
CityGMLChunkWriter
writer
=
factory
.
createCityGMLChunkWriter
(
new
File
(
outputFile
),
StandardCharsets
.
UTF_8
.
name
());
writer
.
withPrefix
(
"qual"
,
QualityADEModule
.
NAMESPACE_URI
);
writer
.
withSchemaLocation
(
QualityADEModule
.
NAMESPACE_URI
,
QualityADEModule
.
NAMESPACE_URI
+
"/qualityAde.xsd"
);
writer
.
withIndent
(
" "
);
writer
.
withDefaultPrefixes
();
writer
.
withDefaultSchemaLocations
();
return
writer
;
}
private
static
CityDoctorModel
readAndKeepFeatures
(
ParserConfiguration
config
,
Path
file
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
return
readAndKeepModel
(
new
Citygml3FeatureMapper
(
config
,
file
),
inputFactory
,
ois
,
verbose
);
}
private
static
CityDoctorModel
readAndKeepModel
(
Citygml3FeatureMapper
mapper
,
CityGMLInputFactory
inputFactory
,
ObservedInputStream
ois
,
boolean
verbose
)
throws
CityGMLReadException
{
try
(
CityGMLReader
reader
=
inputFactory
.
createCityGMLReader
(
ois
))
{
CityGMLVersion
version
=
null
;
// model is read in chunked mode
// object members are replaced by href in model
// need to remove the refs and re-add unparsed objects
List
<
AbstractCityObject
>
acos
=
new
ArrayList
<>();
while
(
reader
.
hasNext
())
{
AbstractFeature
chunk
=
reader
.
next
();
version
=
CityGMLModules
.
getCityGMLVersion
(
reader
.
getName
().
getNamespaceURI
());
if
(
chunk
instanceof
CityModel
cModel
)
{
cModel
.
setCityObjectMembers
(
null
);
mapper
.
setCityModel
(
cModel
);
mapper
.
setCityGMLVersion
(
version
);
}
else
if
(
chunk
instanceof
AbstractCityObject
aco
)
{
acos
.
add
(
aco
);
aco
.
accept
(
mapper
);
}
}
if
(
mapper
.
getModel
().
getCityModel
()
==
null
)
{
// file does not contain a city model?
// create it for now
mapper
.
setCityModel
(
new
CityModel
());
}
CityModel
cModel
=
mapper
.
getModel
().
getCityModel
();
// remove those that should have been parsed
List
<
AbstractCityObject
>
parsedCityObjects
=
mapper
.
getModel
().
createFeatureStream
()
.
map
(
CityObject:
:
getGmlObject
).
toList
();
acos
.
removeAll
(
parsedCityObjects
);
// re-add all not parsed objects
for
(
AbstractCityObject
aco
:
acos
)
{
cModel
.
getCityObjectMembers
().
add
(
new
AbstractCityObjectProperty
(
aco
));
}
if
(
logger
.
isInfoEnabled
()
&&
verbose
)
{
logger
.
info
(
Localization
.
getText
(
"CityGmlParser.parsedObjects"
),
mapper
.
getModel
().
getNumberOfFeatures
());
}
mapper
.
setCityGMLVersion
(
version
);
return
mapper
.
getModel
();
}
}
private
static
void
parseEpsgCodeFromFile
(
Path
file
,
ParserConfiguration
config
)
throws
CityGmlParseException
{
try
(
BufferedInputStream
bis
=
new
BufferedInputStream
(
new
FileInputStream
(
file
.
toFile
())))
{
parseEpsgCodeFromStream
(
bis
,
config
);
}
catch
(
ParserConfigurationException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to read CityGML file"
,
e
);
}
}
private
static
void
parseEpsgCodeFromStream
(
InputStream
is
,
ParserConfiguration
config
)
throws
ParserConfigurationException
,
SAXException
{
SAXParser
parser
=
FACTORY
.
newSAXParser
();
CityGmlHandler
handler
=
new
CityGmlHandler
();
try
{
parser
.
parse
(
new
InputSource
(
is
),
handler
);
}
catch
(
EnvelopeFoundException
e
)
{
try
{
parseCoordinateSystem
(
config
,
handler
);
}
catch
(
Exception
e2
)
{
logEpsgParseError
(
e2
);
}
}
catch
(
Exception
e
)
{
logEpsgParseError
(
e
);
}
}
private
static
void
parseEpsgCodeFromBuffer
(
byte
[]
buffer
,
ParserConfiguration
config
)
throws
ParserConfigurationException
,
SAXException
{
InputStream
is
=
new
ByteArrayInputStream
(
buffer
);
SAXParser
parser
=
FACTORY
.
newSAXParser
();
CityGmlHandler
handler
=
new
CityGmlHandler
();
try
{
parser
.
parse
(
new
InputSource
(
is
),
handler
);
}
catch
(
EnvelopeFoundException
e
)
{
try
{
parseCoordinateSystem
(
config
,
handler
);
}
catch
(
Exception
e2
)
{
logEpsgParseError
(
e2
);
}
}
catch
(
SAXParseException
spe
)
{
// suppress XML document structure warning
if
(!
spe
.
getMessage
().
matches
(
"XML document structures must start and end within the same entity."
))
{
logEpsgParseError
(
spe
);
}
}
catch
(
Exception
e
)
{
logEpsgParseError
(
e
);
}
}
private
static
void
logEpsgParseError
(
Exception
e
)
{
logger
.
debug
(
"Exception while parsing for EPSG code"
,
e
);
if
(
logger
.
isWarnEnabled
())
{
logger
.
warn
(
Localization
.
getText
(
"CityGmlParser.noEPSG"
));
}
}
private
static
void
parseCoordinateSystem
(
ParserConfiguration
config
,
CityGmlHandler
handler
)
{
if
(
handler
.
getEpsg
()
==
null
)
{
return
;
}
CoordinateReferenceSystem
crs
=
crsFromSrsName
(
handler
.
getEpsg
());
if
(
crs
==
null
)
{
// could not find a coordinate system for srsName
// assuming metric system
return
;
}
if
(
crs
.
getProjection
().
getUnits
()
==
Units
.
METRES
)
{
// coordinate system is in meters, do not convert
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"CityGmlParser.noConversionNeeded"
));
}
return
;
}
parseMeterConversion
(
config
,
crs
);
Vector3d
low
=
handler
.
getLowerCorner
();
Vector3d
up
=
handler
.
getUpperCorner
();
double
centerLong
=
low
.
getX
()
+
((
up
.
getX
()
-
low
.
getX
())
/
2
);
double
centerLat
=
low
.
getY
()
+
((
up
.
getY
()
-
low
.
getY
())
/
2
);
if
(!
crs
.
getName
().
equals
(
WGS_84
))
{
// need to convert coordinates first to WGS84, then find UTM Zone
CoordinateReferenceSystem
wgs84
=
crsFromSrsName
(
WGS_84
);
ProjCoordinate
p1
=
new
ProjCoordinate
();
p1
.
setValue
(
centerLong
,
centerLat
);
ProjCoordinate
p2
=
new
ProjCoordinate
();
BasicCoordinateTransform
bct
=
new
BasicCoordinateTransform
(
crs
,
wgs84
);
bct
.
transform
(
p1
,
p2
);
centerLong
=
p2
.
x
;
centerLat
=
p2
.
y
;
}
int
zone
=
(
int
)
(
31
+
Math
.
round
(
centerLong
/
6
));
CoordinateReferenceSystem
utm
;
if
(
centerLat
<
0
)
{
// south
logger
.
info
(
"Converting coordiante system to UTM zone {}S"
,
zone
);
utm
=
CRS_FACTORY
.
createFromParameters
(
"UTM"
,
"+proj=utm +ellps=WGS84 +units=m +zone="
+
zone
+
" +south"
);
}
else
{
// north
logger
.
info
(
"Converting coordiante system to UTM zone {}N"
,
zone
);
utm
=
CRS_FACTORY
.
createFromParameters
(
"UTM"
,
"+proj=utm +ellps=WGS84 +units=m +zone="
+
zone
);
}
config
.
setCoordinateSystem
(
crs
,
utm
);
}
private
static
void
parseMeterConversion
(
ParserConfiguration
config
,
CoordinateReferenceSystem
crs
)
{
Projection
projection
=
crs
.
getProjection
();
double
fromMetres
=
projection
.
getFromMetres
();
if
(
fromMetres
>
0
)
{
// also transform height information
config
.
setFromMeters
(
fromMetres
);
}
else
{
config
.
setFromMeters
(
1.0
);
}
}
/**
* The srsName (The name by which this reference system is identified) inside
* the CityGML file can have multiple formats. This method tries to parse the
* string and detect the corresponding reference system. If it is found, it
* returns a proj4j.CoordinateReferenceSystem. It throws an
* IllegalArgumentException otherwise.
* <p>
* This method should be able to parse any EPSG id : e.g. "EPSG:1234". German
* Citygmls might also have "DE_DHDN_3GK3" or "ETRS89_UTM32" as srsName, so
* those are also included. It isn't guaranteed that those formats are correctly
* parsed, though.
* <p>
* The EPSG ids and parameters are defined in resources ('nad/epsg') inside
* proj4j-0.1.0.jar. Some EPSG ids are missing though, e.g. 7415
*
* @param srsName
* @return CoordinateReferenceSystem
*/
private
static
CoordinateReferenceSystem
crsFromSrsName
(
String
srsName
)
{
srsName
=
srsName
.
trim
();
Matcher
mEPSG
=
P_EPSG
.
matcher
(
srsName
);
if
(
mEPSG
.
find
())
{
if
(
"EPSG:4979"
.
contentEquals
(
srsName
))
{
srsName
=
"EPSG:4236"
;
}
else
if
(
"EPSG:7415"
.
contentEquals
(
srsName
))
{
return
CRS_FACTORY
.
createFromParameters
(
"EPSG:7415"
,
"+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs"
);
}
return
CRS_FACTORY
.
createFromName
(
srsName
);
}
Matcher
mOGC
=
P_OGC
.
matcher
(
srsName
);
if
(
mOGC
.
find
())
{
return
CRS_FACTORY
.
createFromName
(
"EPSG:"
+
mOGC
.
group
(
1
));
}
Matcher
mOGC2
=
P_OGC2
.
matcher
(
srsName
);
if
(
mOGC2
.
find
())
{
return
CRS_FACTORY
.
createFromName
(
"EPSG:"
+
mOGC2
.
group
(
1
));
}
Matcher
mURN
=
P_URN
.
matcher
(
srsName
);
// NOTE: Could use a HashMap if the switch/case becomes too long.
if
(
mURN
.
find
())
{
return
switch
(
mURN
.
group
(
1
))
{
case
"DE_DHDN_3GK2"
->
CRS_FACTORY
.
createFromName
(
"EPSG:31466"
);
case
"DE_DHDN_3GK3"
->
CRS_FACTORY
.
createFromName
(
"EPSG:31467"
);
...
...
@@ -676,59 +682,59 @@ public class CityGmlParser {
case
"ETRS89_UTM32"
->
CRS_FACTORY
.
createFromName
(
"EPSG:25832"
);
default
->
null
;
};
}
if
(
srsName
.
equals
(
"http://www.opengis.net/def/crs/EPSG/0/6697"
))
{
return
CRS_FACTORY
.
createFromParameters
(
"EPSG:6697"
,
"+proj=longlat +ellps=GRS80 +no_defs +axis=neu"
);
}
return
null
;
}
private
static
List
<
String
>
validateFile
(
CityGMLContext
context
,
GMLValidationHandler
handler
,
Path
file
)
throws
CityGmlParseException
{
if
(
handler
==
null
)
{
handler
=
new
GMLValidationHandler
();
}
try
{
SchemaHandler
schemaHandler
=
new
ValidationSchemaHandler
(
context
.
getDefaultSchemaHandler
());
}
if
(
srsName
.
equals
(
"http://www.opengis.net/def/crs/EPSG/0/6697"
))
{
return
CRS_FACTORY
.
createFromParameters
(
"EPSG:6697"
,
"+proj=longlat +ellps=GRS80 +no_defs +axis=neu"
);
}
return
null
;
}
private
static
List
<
String
>
validateFile
(
CityGMLContext
context
,
GMLValidationHandler
handler
,
Path
file
)
throws
CityGmlParseException
{
if
(
handler
==
null
)
{
handler
=
new
GMLValidationHandler
();
}
try
{
SchemaHandler
schemaHandler
=
new
ValidationSchemaHandler
(
context
.
getDefaultSchemaHandler
());
readAdditionalSchemaDefinitions
(
context
,
file
,
schemaHandler
);
Source
[]
schemas
=
schemaHandler
.
getSchemas
();
SchemaFactory
schemaFactory
=
SchemaFactory
.
newInstance
(
XMLConstants
.
W3C_XML_SCHEMA_NS_URI
);
schemaFactory
.
setFeature
(
"http://apache.org/xml/features/disallow-doctype-decl"
,
true
);
Schema
schema
=
schemaFactory
.
newSchema
(
schemas
);
Validator
validator
=
schema
.
newValidator
();
validator
.
setErrorHandler
(
handler
);
validator
.
validate
(
new
StreamSource
(
file
.
toFile
()));
return
handler
.
getMessages
();
}
catch
(
SchemaHandlerException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to validate CityGML file"
,
e
);
}
}
private
static
void
readAdditionalSchemaDefinitions
(
CityGMLContext
context
,
Path
file
,
SchemaHandler
schemaHandler
)
throws
CityGmlParseException
{
try
(
XMLReader
reader
=
XMLReaderFactory
.
newInstance
(
context
.
getXMLObjects
())
.
withSchemaHandler
(
schemaHandler
)
.
createReader
(
file
))
{
reader
.
nextTag
();
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
"Failed to read file "
+
file
.
toAbsolutePath
()
+
"."
,
e
);
}
}
private
static
void
drainCityModel
(
CityDoctorModel
model
,
CityGmlConsumer
cityObjectConsumer
)
{
drainCityObjectList
(
model
.
getBuildings
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getBridges
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getVegetation
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getLand
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getTransportation
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getWater
(),
cityObjectConsumer
);
}
private
static
void
drainCityObjectList
(
List
<?
extends
CityObject
>
objects
,
CityGmlConsumer
cityObjectConsumer
)
{
for
(
CityObject
co
:
objects
)
{
cityObjectConsumer
.
accept
(
co
);
}
objects
.
clear
();
}
Source
[]
schemas
=
schemaHandler
.
getSchemas
();
SchemaFactory
schemaFactory
=
SchemaFactory
.
newInstance
(
XMLConstants
.
W3C_XML_SCHEMA_NS_URI
);
schemaFactory
.
setFeature
(
"http://apache.org/xml/features/disallow-doctype-decl"
,
true
);
Schema
schema
=
schemaFactory
.
newSchema
(
schemas
);
Validator
validator
=
schema
.
newValidator
();
validator
.
setErrorHandler
(
handler
);
validator
.
validate
(
new
StreamSource
(
file
.
toFile
()));
return
handler
.
getMessages
();
}
catch
(
SchemaHandlerException
|
SAXException
|
IOException
e
)
{
throw
new
CityGmlParseException
(
"Failed to validate CityGML file"
,
e
);
}
}
private
static
void
readAdditionalSchemaDefinitions
(
CityGMLContext
context
,
Path
file
,
SchemaHandler
schemaHandler
)
throws
CityGmlParseException
{
try
(
XMLReader
reader
=
XMLReaderFactory
.
newInstance
(
context
.
getXMLObjects
())
.
withSchemaHandler
(
schemaHandler
)
.
createReader
(
file
))
{
reader
.
nextTag
();
}
catch
(
Exception
e
)
{
throw
new
CityGmlParseException
(
"Failed to read file "
+
file
.
toAbsolutePath
()
+
"."
,
e
);
}
}
private
static
void
drainCityModel
(
CityDoctorModel
model
,
CityGmlConsumer
cityObjectConsumer
)
{
drainCityObjectList
(
model
.
getBuildings
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getBridges
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getVegetation
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getLand
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getTransportation
(),
cityObjectConsumer
);
drainCityObjectList
(
model
.
getWater
(),
cityObjectConsumer
);
}
private
static
void
drainCityObjectList
(
List
<?
extends
CityObject
>
objects
,
CityGmlConsumer
cityObjectConsumer
)
{
for
(
CityObject
co
:
objects
)
{
cityObjectConsumer
.
accept
(
co
);
}
objects
.
clear
();
}
}
This diff is collapsed.
Click to expand it.
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipArchive.java
+
13
-
12
View file @
671c277b
...
...
@@ -5,12 +5,14 @@ import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
java.io.*
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.nio.file.Path
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
java.util.zip.ZipInputStream
;
...
...
@@ -32,8 +34,7 @@ public class CityGmlZipArchive implements Serializable {
CityGmlZipArchive
cgmlArchive
=
new
CityGmlZipArchive
(
Path
.
of
(
zipFile
));
try
(
ZipInputStream
zis
=
new
ZipInputStream
(
new
FileInputStream
(
zipFile
)))
{
ZipEntry
ze
;
while
((
ze
=
zis
.
getNextEntry
())
!=
null
)
{
while
((
ze
=
zis
.
getNextEntry
())
!=
null
)
{
if
(
ze
.
isDirectory
())
{
continue
;
}
...
...
@@ -49,9 +50,9 @@ public class CityGmlZipArchive implements Serializable {
}
}
public
void
mountArchive
(
ParserConfiguration
config
){
public
void
mountArchive
(
ParserConfiguration
config
)
{
try
(
ZipFile
zip
=
new
ZipFile
(
archivePath
.
toFile
()))
{
for
(
CityGmlZipEntry
entry
:
entries
){
for
(
CityGmlZipEntry
entry
:
entries
)
{
entry
.
loadEntry
(
config
);
}
}
catch
(
IOException
e
)
{
...
...
@@ -59,9 +60,9 @@ public class CityGmlZipArchive implements Serializable {
}
}
private
CityGmlZipArchive
(
Path
archivePath
){
private
CityGmlZipArchive
(
Path
archivePath
)
{
this
.
archivePath
=
archivePath
;
this
.
archiveNameRE
=
archivePath
.
getFileName
().
toString
().
replace
(
".zip"
,
""
)
+
File
.
separator
;
this
.
archiveNameRE
=
archivePath
.
getFileName
().
toString
().
replace
(
".zip"
,
""
)
+
File
.
separator
;
}
private
void
setEntries
(
List
<
CityGmlZipEntry
>
entries
)
{
...
...
@@ -69,16 +70,16 @@ public class CityGmlZipArchive implements Serializable {
entries
.
forEach
(
e
->
e
.
setArchive
(
this
));
}
public
void
exportToZipFile
(
String
path
)
{
public
void
exportToZipFile
(
String
path
)
{
ArchivePacker
.
packArchive
(
path
,
this
);
}
public
CityGmlZipEntry
getEntry
(
String
fileName
)
{
fileName
=
stripArchivePath
(
fileName
);
for
(
CityGmlZipEntry
entry
:
entries
){
for
(
CityGmlZipEntry
entry
:
entries
)
{
String
entryName
=
stripArchivePath
(
entry
.
getFileName
());
if
(
entryName
.
equals
(
fileName
)){
if
(
entryName
.
equals
(
fileName
))
{
return
entry
;
}
}
...
...
This diff is collapsed.
Click to expand it.
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/zip/CityGmlZipEntry.java
+
18
-
19
View file @
671c277b
...
...
@@ -27,39 +27,39 @@ public class CityGmlZipEntry implements Serializable {
private
static
final
long
MB
=
1024
*
1024L
;
private
ZipEntryErrorType
errorType
=
null
;
public
static
CityGmlZipEntry
of
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
,
ParserConfiguration
config
){
public
static
CityGmlZipEntry
of
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
,
ParserConfiguration
config
)
{
CityGmlZipEntry
ze
=
CityGmlZipEntry
.
register
(
entry
,
parentArchive
);
ze
.
loadEntry
(
config
);
return
ze
;
}
public
void
loadEntry
(
ParserConfiguration
config
){
if
(
decompressed
){
public
void
loadEntry
(
ParserConfiguration
config
)
{
if
(
decompressed
)
{
return
;
}
if
(
errorType
!=
null
){
if
(
errorType
!=
null
)
{
logger
.
warn
(
"Tried loading erroneous CityGmlZipEntry"
);
return
;
}
try
{
try
{
this
.
model
=
CityGmlParser
.
parseCityGmlZipEntry
(
this
,
config
);
this
.
decompressed
=
true
;
}
catch
(
CityGmlParseException
|
InvalidGmlFileException
e
)
{
logger
.
error
(
e
);
this
.
errorType
=
ZipEntryErrorType
.
INVALID_CITY_GML_FILE
;
}
catch
(
IOException
e
){
}
catch
(
IOException
e
)
{
logger
.
error
(
e
);
this
.
errorType
=
ZipEntryErrorType
.
IO_ERROR
;
}
}
public
static
CityGmlZipEntry
register
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
){
CityGmlZipEntry
cgzEntry
=
new
CityGmlZipEntry
(
entry
,
parentArchive
,
false
);
try
{
public
static
CityGmlZipEntry
register
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
)
{
CityGmlZipEntry
cgzEntry
=
new
CityGmlZipEntry
(
entry
,
parentArchive
,
false
);
try
{
if
(!
cgzEntry
.
entrySizeWithinMemoryLimits
())
{
cgzEntry
.
errorType
=
ZipEntryErrorType
.
EXCESSIVE_FILESIZE
;
}
}
catch
(
IOException
e
){
}
catch
(
IOException
e
)
{
logger
.
error
(
e
);
cgzEntry
.
errorType
=
ZipEntryErrorType
.
IO_ERROR
;
}
...
...
@@ -67,11 +67,11 @@ public class CityGmlZipEntry implements Serializable {
}
private
boolean
entrySizeWithinMemoryLimits
()
throws
IOException
{
long
memoryLimit
=
(
long
)
Math
.
ceil
(((
double
)
Runtime
.
getRuntime
().
maxMemory
()
/
MB
)
*
0.9
);
long
memoryLimit
=
(
long
)
Math
.
ceil
(((
double
)
Runtime
.
getRuntime
().
maxMemory
()
/
MB
)
*
0.9
);
if
(
fileSize
==
-
1L
)
{
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
this
)){
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
this
))
{
long
filesize
=
entryFile
.
getFileSize
();
if
(
filesize
!=
-
1
){
if
(
filesize
!=
-
1
)
{
this
.
fileSize
=
filesize
;
}
else
{
return
false
;
...
...
@@ -83,9 +83,9 @@ public class CityGmlZipEntry implements Serializable {
return
memoryLimit
>
fileSize
;
}
protected
CityGmlZipEntry
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
,
boolean
decompressed
)
{
protected
CityGmlZipEntry
(
ZipEntry
entry
,
CityGmlZipArchive
parentArchive
,
boolean
decompressed
)
{
this
.
fileName
=
entry
.
getName
();
if
(
entry
.
getSize
()
!=
-
1
){
if
(
entry
.
getSize
()
!=
-
1
)
{
this
.
fileSize
=
entry
.
getSize
();
}
this
.
model
=
null
;
...
...
@@ -93,15 +93,14 @@ public class CityGmlZipEntry implements Serializable {
this
.
parentArchive
=
parentArchive
;
}
public
void
setArchive
(
CityGmlZipArchive
archive
){
public
void
setArchive
(
CityGmlZipArchive
archive
)
{
parentArchive
=
archive
;
}
public
CityGmlZipArchive
getArchive
(){
public
CityGmlZipArchive
getArchive
()
{
return
parentArchive
;
}
public
String
getFileName
()
{
return
fileName
;
}
...
...
@@ -118,7 +117,7 @@ public class CityGmlZipEntry implements Serializable {
fileSize
=
size
;
}
public
long
getFileSize
(){
public
long
getFileSize
()
{
return
fileSize
;
}
}
This diff is collapsed.
Click to expand it.
CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/zip/ZipTest.java
+
10
-
7
View file @
671c277b
...
...
@@ -9,11 +9,14 @@ import java.io.IOException;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
public
class
ZipTest
{
ParserConfiguration
config
=
new
ParserConfiguration
(
8
,
false
);
ParserConfiguration
config
=
new
ParserConfiguration
(
8
,
false
);
@Test
...
...
@@ -25,8 +28,8 @@ public class ZipTest {
checkMockArchive
(
cgmlArch
);
}
private
void
checkMockArchive
(
CityGmlZipArchive
cgmlArch
){
assertEquals
(
5
,
cgmlArch
.
getEntries
().
size
());
private
void
checkMockArchive
(
CityGmlZipArchive
cgmlArch
)
{
assertEquals
(
5
,
cgmlArch
.
getEntries
().
size
());
for
(
CityGmlZipEntry
entry
:
cgmlArch
.
getEntries
())
{
assertNotNull
(
entry
);
assertTrue
(
entry
.
getFileName
().
matches
(
"^mock[1-5].gml$"
));
...
...
@@ -79,8 +82,8 @@ public class ZipTest {
}
@Test
public
void
testXMLValidation
(){
ParserConfiguration
valConfig
=
new
ParserConfiguration
(
8
,
true
);
public
void
testXMLValidation
()
{
ParserConfiguration
valConfig
=
new
ParserConfiguration
(
8
,
true
);
CityGmlZipArchive
cgmlArch
=
CityGmlZipArchive
.
register
(
"src/test/resources/zip/validate.zip"
);
assertNotNull
(
cgmlArch
);
cgmlArch
.
mountArchive
(
valConfig
);
...
...
@@ -91,7 +94,7 @@ public class ZipTest {
@Test
public
void
testImplicitParsing
(){
public
void
testImplicitParsing
()
{
CityGmlZipArchive
cgmlArch
=
CityGmlZipArchive
.
register
(
"src/test/resources/zip/implicit.zip"
);
assertNotNull
(
cgmlArch
);
cgmlArch
.
mountArchive
(
config
);
...
...
This diff is collapsed.
Click to expand it.
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java
+
778
-
781
View file @
671c277b
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
...
...
@@ -18,41 +18,6 @@
*/
package
de.hft.stuttgart.citydoctor2.check
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.UncheckedIOException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.stream.Stream
;
import
javax.xml.XMLConstants
;
import
javax.xml.transform.Result
;
import
javax.xml.transform.Source
;
import
javax.xml.transform.Transformer
;
import
javax.xml.transform.TransformerException
;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.dom.DOMResult
;
import
javax.xml.transform.dom.DOMSource
;
import
javax.xml.transform.sax.SAXResult
;
import
javax.xml.transform.stream.StreamSource
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.check.error.AttributeInvalidError
;
import
de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError
;
import
de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError
;
...
...
@@ -78,6 +43,8 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import
de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter
;
import
de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter
;
import
de.hft.stuttgart.citydoctor2.utils.Localization
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntryFile
;
import
de.hft.stuttgart.quality.model.enums.RequirementId
;
import
de.hft.stuttgart.quality.model.enums.TopLevelFeatureType
;
import
de.hft.stuttgart.quality.model.properties.CheckingProperty
;
...
...
@@ -88,309 +55,339 @@ import de.hft.stuttgart.quality.model.properties.RequirementProperty;
import
de.hft.stuttgart.quality.model.types.Checking
;
import
de.hft.stuttgart.quality.model.types.Parameter
;
import
de.hft.stuttgart.quality.model.types.ValidationPlan
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
javax.xml.XMLConstants
;
import
javax.xml.transform.Result
;
import
javax.xml.transform.Source
;
import
javax.xml.transform.Transformer
;
import
javax.xml.transform.TransformerException
;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.dom.DOMResult
;
import
javax.xml.transform.dom.DOMSource
;
import
javax.xml.transform.sax.SAXResult
;
import
javax.xml.transform.stream.StreamSource
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.UncheckedIOException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.stream.Stream
;
/**
* The main container class for checking. It contains the logic for validation,
* as well as contains the state of the checks performed.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public
class
Checker
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
Checker
.
class
);
private
ValidationConfiguration
config
;
private
List
<
List
<
Check
>>
execLayers
;
private
List
<
Filter
>
includeFilters
;
private
List
<
Filter
>
excludeFilters
;
private
final
Checks
checkConfig
;
private
final
CityDoctorModel
model
;
public
Checker
(
CityDoctorModel
model
)
{
this
(
ValidationConfiguration
.
loadStandardValidationConfig
(),
model
);
}
public
Checker
(
ValidationConfiguration
config
,
CityDoctorModel
model
)
{
this
.
model
=
model
;
checkConfig
=
new
Checks
();
setValidationConfig
(
config
);
}
public
Checks
getChecks
()
{
return
checkConfig
;
}
public
CityDoctorModel
getModel
()
{
return
model
;
}
/**
* Write the xml report for the given CityDoctorModel. If no report location is
* given or this checker has not validated anything, nothing is done.
*
* @param xmlOutput the output file location for the XML report. Can be null.
*/
public
void
writeXmlReport
(
String
xmlOutput
)
{
if
(!
model
.
isValidated
()
||
xmlOutput
==
null
)
{
return
;
}
File
xmlFile
=
new
File
(
xmlOutput
);
if
(
xmlFile
.
getParentFile
()
!=
null
)
{
xmlFile
.
getParentFile
().
mkdirs
();
}
Reporter
reporter
=
new
XmlValidationReporter
();
try
(
BufferedOutputStream
bos
=
new
BufferedOutputStream
(
new
FileOutputStream
(
xmlFile
.
getAbsolutePath
())))
{
reporter
.
writeReport
(
checkConfig
,
bos
,
model
,
config
);
}
catch
(
CheckReportWriteException
|
IOException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failXml"
),
e
);
}
}
public
void
writePdfReport
(
String
pdfOutput
)
{
if
(!
model
.
isValidated
()
||
pdfOutput
==
null
)
{
return
;
}
File
pdfFile
=
new
File
(
pdfOutput
);
if
(
pdfFile
.
getParentFile
()
!=
null
)
{
pdfFile
.
getParentFile
().
mkdirs
();
}
Reporter
reporter
=
new
PdfReporter
();
try
(
BufferedOutputStream
bos
=
new
BufferedOutputStream
(
new
FileOutputStream
(
pdfFile
.
getAbsolutePath
())))
{
reporter
.
writeReport
(
checkConfig
,
bos
,
model
,
config
);
}
catch
(
IOException
|
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failPdf"
),
e
);
}
}
public
void
runChecks
()
{
runChecks
((
ProgressListener
)
null
);
}
public
void
runChecks
(
String
xmlOutput
)
{
runChecks
();
writeXmlReport
(
xmlOutput
);
}
public
void
runChecks
(
String
xmlOutput
,
String
pdfOutput
)
{
runChecks
();
writeXmlReport
(
xmlOutput
);
writePdfReport
(
pdfOutput
);
}
public
void
runChecks
(
String
xmlOutput
,
String
pdfOutput
,
ProgressListener
l
)
{
runChecks
(
l
);
writeXmlReport
(
xmlOutput
);
writePdfReport
(
pdfOutput
);
}
public
void
runChecks
(
ProgressListener
l
)
{
if
(
config
==
null
)
{
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
}
checkCityModel
(
model
,
l
);
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"Checker.checksFinished"
));
}
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
model
.
getFile
());
if
(
handler
!=
null
)
{
handleSchematronResults
(
handler
);
}
model
.
setValidated
(
createValidationPlan
());
}
private
void
handleSchematronResults
(
SvrlContentHandler
handler
)
{
model
.
addGlobalErrors
(
handler
.
getGeneralErrors
());
Map
<
String
,
CityObject
>
featureMap
=
new
HashMap
<>();
model
.
createFeatureStream
().
forEach
(
f
->
featureMap
.
put
(
f
.
getGmlId
().
getGmlString
(),
f
));
handler
.
getFeatureErrors
().
forEach
((
k
,
v
)
->
{
if
(
k
.
trim
().
isEmpty
())
{
// missing gml id, ignore?
return
;
}
CityObject
co
=
featureMap
.
get
(
k
);
if
(
co
==
null
)
{
// gml id reported by schematron was not found, add to general errors
for
(
SchematronError
se
:
v
)
{
model
.
addGlobalError
(
se
);
}
}
else
{
handleSchematronErrorsForCityObject
(
v
,
co
);
}
});
}
public
static
void
handleSchematronErrorsForCityObject
(
List
<
SchematronError
>
v
,
CityObject
co
)
{
int
count
=
0
;
for
(
SchematronError
se
:
v
)
{
CheckError
err
;
if
(
AttributeMissingError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeMissingError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
if
(
AttributeValueWrongError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeValueWrongError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
if
(
AttributeInvalidError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeInvalidError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
{
throw
new
IllegalStateException
(
"Unknown error ID was given in schematron file: "
+
se
.
getErrorIdString
());
}
co
.
addCheckResult
(
new
CheckResult
(
new
CheckId
(
"SchematronCheck "
+
count
),
ResultStatus
.
ERROR
,
err
));
count
++;
}
}
ValidationPlan
createValidationPlan
()
{
ValidationPlan
plan
=
new
ValidationPlan
();
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
=
createFilter
();
plan
.
setFilter
(
new
FilterProperty
(
filter
));
Map
<
String
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
>
reqs
=
Checks
.
getAvailableRequirements
();
for
(
Entry
<
String
,
RequirementConfiguration
>
e
:
config
.
getRequirements
().
entrySet
())
{
RequirementId
reqId
=
mapToRequirement
(
e
.
getKey
());
if
(
reqId
==
null
)
{
continue
;
}
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
req
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
req
.
setRequirementType
(
reqId
);
req
.
setEnabled
(
e
.
getValue
().
isEnabled
());
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
req
));
Map
<
String
,
String
>
parameters
=
e
.
getValue
().
getParameters
();
if
(
parameters
!=
null
)
{
for
(
Entry
<
String
,
String
>
param
:
parameters
.
entrySet
())
{
Parameter
p
=
new
Parameter
();
DefaultParameter
defaultP
=
getDefaultParameter
(
e
.
getKey
(),
reqs
,
param
.
getKey
());
if
(
defaultP
!=
null
)
{
p
.
setUom
(
defaultP
.
getUnitType
().
getGmlRepresentation
());
}
p
.
setName
(
param
.
getKey
());
p
.
setValue
(
param
.
getValue
());
req
.
getParameters
().
add
(
new
ParameterProperty
(
p
));
}
}
}
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
missing
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
missing
.
setRequirementType
(
RequirementId
.
R_SE_ATTRIBUTES_EXISTING
);
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
correct
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
correct
.
setRequirementType
(
RequirementId
.
R_SE_ATTRIBUTES_CORRECT
);
missing
.
setEnabled
(
config
.
getSchematronFilePath
()
!=
null
);
correct
.
setEnabled
(
config
.
getSchematronFilePath
()
!=
null
);
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
missing
));
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
correct
));
Parameter
numRounding
=
new
Parameter
();
numRounding
.
setName
(
"numberOfRoundingPlaces"
);
numRounding
.
setValue
(
""
+
config
.
getNumberOfRoundingPlaces
());
Parameter
minVertexDistance
=
new
Parameter
();
minVertexDistance
.
setName
(
"minVertexDistance"
);
minVertexDistance
.
setUom
(
"m"
);
minVertexDistance
.
setValue
(
""
+
config
.
getMinVertexDistance
());
Parameter
schematronFile
=
new
Parameter
();
schematronFile
.
setName
(
"schematronFile"
);
schematronFile
.
setValue
(
config
.
getSchematronFilePath
());
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
GlobalParameters
globParams
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
GlobalParameters
();
plan
.
setGlobalParameters
(
new
GlobalParametersProperty
(
globParams
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
numRounding
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
minVertexDistance
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
schematronFile
));
return
plan
;
}
private
DefaultParameter
getDefaultParameter
(
String
reqKey
,
Map
<
String
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
>
reqs
,
String
paramName
)
{
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
requirement
=
reqs
.
get
(
reqKey
);
if
(
requirement
!=
null
)
{
for
(
DefaultParameter
param
:
requirement
.
getDefaultParameter
())
{
if
(
param
.
getName
().
equals
(
paramName
))
{
return
param
;
}
}
}
return
null
;
}
private
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
createFilter
()
{
var
filter
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
();
handleInputFilter
(
filter
);
if
(
excludeFilters
!=
null
)
{
for
(
Filter
f
:
excludeFilters
)
{
if
(
f
instanceof
TypeFilter
tf
)
{
FeatureType
type
=
tf
.
getType
();
TopLevelFeatureType
tlft
=
mapToTopLevelFeatureType
(
type
);
if
(
tlft
==
null
)
{
continue
;
}
removeFilter
(
tlft
,
filter
);
}
}
}
return
filter
;
}
private
void
handleInputFilter
(
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
if
(
includeFilters
==
null
||
includeFilters
.
isEmpty
())
{
// no filter means, use all
addAllFilters
(
filter
);
}
else
{
for
(
Filter
f
:
includeFilters
)
{
if
(
f
instanceof
TypeFilter
tf
)
{
FeatureType
type
=
tf
.
getType
();
TopLevelFeatureType
tlft
=
mapToTopLevelFeatureType
(
type
);
if
(
tlft
==
null
)
{
continue
;
}
Checking
c
=
new
Checking
();
c
.
setFeatureType
(
tlft
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
c
));
}
}
if
(
filter
.
getChecking
().
isEmpty
())
{
// this happens if no type include filter was used
// it is possible only single objects were tested then
// so include everything
addAllFilters
(
filter
);
}
}
}
private
void
addAllFilters
(
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
Checking
buildingChecking
=
new
Checking
();
buildingChecking
.
setFeatureType
(
TopLevelFeatureType
.
BUILDING
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
buildingChecking
));
Checking
bridgeChecking
=
new
Checking
();
bridgeChecking
.
setFeatureType
(
TopLevelFeatureType
.
BRIDGE
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
bridgeChecking
));
Checking
landChecking
=
new
Checking
();
landChecking
.
setFeatureType
(
TopLevelFeatureType
.
LAND
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
landChecking
));
Checking
transportationChecking
=
new
Checking
();
transportationChecking
.
setFeatureType
(
TopLevelFeatureType
.
TRANSPORTATION
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
transportationChecking
));
Checking
vegetationChecking
=
new
Checking
();
vegetationChecking
.
setFeatureType
(
TopLevelFeatureType
.
VEGETATION
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
vegetationChecking
));
Checking
waterChecking
=
new
Checking
();
waterChecking
.
setFeatureType
(
TopLevelFeatureType
.
WATER
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
waterChecking
));
}
private
void
removeFilter
(
TopLevelFeatureType
tlft
,
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
for
(
CheckingProperty
c
:
filter
.
getChecking
())
{
if
(
c
.
getObject
().
getFeatureType
().
equals
(
tlft
))
{
filter
.
getChecking
().
remove
(
c
);
return
;
}
}
}
private
TopLevelFeatureType
mapToTopLevelFeatureType
(
FeatureType
type
)
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
Checker
.
class
);
private
ValidationConfiguration
config
;
private
List
<
List
<
Check
>>
execLayers
;
private
List
<
Filter
>
includeFilters
;
private
List
<
Filter
>
excludeFilters
;
private
final
Checks
checkConfig
;
private
final
CityDoctorModel
model
;
public
Checker
(
CityDoctorModel
model
)
{
this
(
ValidationConfiguration
.
loadStandardValidationConfig
(),
model
);
}
public
Checker
(
ValidationConfiguration
config
,
CityDoctorModel
model
)
{
this
.
model
=
model
;
checkConfig
=
new
Checks
();
setValidationConfig
(
config
);
}
public
Checks
getChecks
()
{
return
checkConfig
;
}
public
CityDoctorModel
getModel
()
{
return
model
;
}
/**
* Write the xml report for the given CityDoctorModel. If no report location is
* given or this checker has not validated anything, nothing is done.
*
* @param xmlOutput the output file location for the XML report. Can be null.
*/
public
void
writeXmlReport
(
String
xmlOutput
)
{
if
(!
model
.
isValidated
()
||
xmlOutput
==
null
)
{
return
;
}
File
xmlFile
=
new
File
(
xmlOutput
);
if
(
xmlFile
.
getParentFile
()
!=
null
)
{
xmlFile
.
getParentFile
().
mkdirs
();
}
Reporter
reporter
=
new
XmlValidationReporter
();
try
(
BufferedOutputStream
bos
=
new
BufferedOutputStream
(
new
FileOutputStream
(
xmlFile
.
getAbsolutePath
())))
{
reporter
.
writeReport
(
checkConfig
,
bos
,
model
,
config
);
}
catch
(
CheckReportWriteException
|
IOException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failXml"
),
e
);
}
}
public
void
writePdfReport
(
String
pdfOutput
)
{
if
(!
model
.
isValidated
()
||
pdfOutput
==
null
)
{
return
;
}
File
pdfFile
=
new
File
(
pdfOutput
);
if
(
pdfFile
.
getParentFile
()
!=
null
)
{
pdfFile
.
getParentFile
().
mkdirs
();
}
Reporter
reporter
=
new
PdfReporter
();
try
(
BufferedOutputStream
bos
=
new
BufferedOutputStream
(
new
FileOutputStream
(
pdfFile
.
getAbsolutePath
())))
{
reporter
.
writeReport
(
checkConfig
,
bos
,
model
,
config
);
}
catch
(
IOException
|
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failPdf"
),
e
);
}
}
public
void
runChecks
()
{
runChecks
((
ProgressListener
)
null
);
}
public
void
runChecks
(
String
xmlOutput
)
{
runChecks
();
writeXmlReport
(
xmlOutput
);
}
public
void
runChecks
(
String
xmlOutput
,
String
pdfOutput
)
{
runChecks
();
writeXmlReport
(
xmlOutput
);
writePdfReport
(
pdfOutput
);
}
public
void
runChecks
(
String
xmlOutput
,
String
pdfOutput
,
ProgressListener
l
)
{
runChecks
(
l
);
writeXmlReport
(
xmlOutput
);
writePdfReport
(
pdfOutput
);
}
public
void
runChecks
(
ProgressListener
l
)
{
if
(
config
==
null
)
{
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
}
checkCityModel
(
model
,
l
);
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"Checker.checksFinished"
));
}
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
model
.
getFile
());
if
(
handler
!=
null
)
{
handleSchematronResults
(
handler
);
}
model
.
setValidated
(
createValidationPlan
());
}
private
void
handleSchematronResults
(
SvrlContentHandler
handler
)
{
model
.
addGlobalErrors
(
handler
.
getGeneralErrors
());
Map
<
String
,
CityObject
>
featureMap
=
new
HashMap
<>();
model
.
createFeatureStream
().
forEach
(
f
->
featureMap
.
put
(
f
.
getGmlId
().
getGmlString
(),
f
));
handler
.
getFeatureErrors
().
forEach
((
k
,
v
)
->
{
if
(
k
.
trim
().
isEmpty
())
{
// missing gml id, ignore?
return
;
}
CityObject
co
=
featureMap
.
get
(
k
);
if
(
co
==
null
)
{
// gml id reported by schematron was not found, add to general errors
for
(
SchematronError
se
:
v
)
{
model
.
addGlobalError
(
se
);
}
}
else
{
handleSchematronErrorsForCityObject
(
v
,
co
);
}
});
}
public
static
void
handleSchematronErrorsForCityObject
(
List
<
SchematronError
>
v
,
CityObject
co
)
{
int
count
=
0
;
for
(
SchematronError
se
:
v
)
{
CheckError
err
;
if
(
AttributeMissingError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeMissingError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
if
(
AttributeValueWrongError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeValueWrongError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
if
(
AttributeInvalidError
.
ID
.
getIdString
().
equals
(
se
.
getErrorIdString
()))
{
err
=
new
AttributeInvalidError
(
co
,
se
.
getChildId
(),
se
.
getNameOfAttribute
());
}
else
{
throw
new
IllegalStateException
(
"Unknown error ID was given in schematron file: "
+
se
.
getErrorIdString
());
}
co
.
addCheckResult
(
new
CheckResult
(
new
CheckId
(
"SchematronCheck "
+
count
),
ResultStatus
.
ERROR
,
err
));
count
++;
}
}
ValidationPlan
createValidationPlan
()
{
ValidationPlan
plan
=
new
ValidationPlan
();
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
=
createFilter
();
plan
.
setFilter
(
new
FilterProperty
(
filter
));
Map
<
String
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
>
reqs
=
Checks
.
getAvailableRequirements
();
for
(
Entry
<
String
,
RequirementConfiguration
>
e
:
config
.
getRequirements
().
entrySet
())
{
RequirementId
reqId
=
mapToRequirement
(
e
.
getKey
());
if
(
reqId
==
null
)
{
continue
;
}
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
req
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
req
.
setRequirementType
(
reqId
);
req
.
setEnabled
(
e
.
getValue
().
isEnabled
());
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
req
));
Map
<
String
,
String
>
parameters
=
e
.
getValue
().
getParameters
();
if
(
parameters
!=
null
)
{
for
(
Entry
<
String
,
String
>
param
:
parameters
.
entrySet
())
{
Parameter
p
=
new
Parameter
();
DefaultParameter
defaultP
=
getDefaultParameter
(
e
.
getKey
(),
reqs
,
param
.
getKey
());
if
(
defaultP
!=
null
)
{
p
.
setUom
(
defaultP
.
getUnitType
().
getGmlRepresentation
());
}
p
.
setName
(
param
.
getKey
());
p
.
setValue
(
param
.
getValue
());
req
.
getParameters
().
add
(
new
ParameterProperty
(
p
));
}
}
}
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
missing
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
missing
.
setRequirementType
(
RequirementId
.
R_SE_ATTRIBUTES_EXISTING
);
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
correct
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Requirement
();
correct
.
setRequirementType
(
RequirementId
.
R_SE_ATTRIBUTES_CORRECT
);
missing
.
setEnabled
(
config
.
getSchematronFilePath
()
!=
null
);
correct
.
setEnabled
(
config
.
getSchematronFilePath
()
!=
null
);
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
missing
));
plan
.
getRequirements
().
add
(
new
RequirementProperty
(
correct
));
Parameter
numRounding
=
new
Parameter
();
numRounding
.
setName
(
"numberOfRoundingPlaces"
);
numRounding
.
setValue
(
""
+
config
.
getNumberOfRoundingPlaces
());
Parameter
minVertexDistance
=
new
Parameter
();
minVertexDistance
.
setName
(
"minVertexDistance"
);
minVertexDistance
.
setUom
(
"m"
);
minVertexDistance
.
setValue
(
""
+
config
.
getMinVertexDistance
());
Parameter
schematronFile
=
new
Parameter
();
schematronFile
.
setName
(
"schematronFile"
);
schematronFile
.
setValue
(
config
.
getSchematronFilePath
());
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
GlobalParameters
globParams
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
GlobalParameters
();
plan
.
setGlobalParameters
(
new
GlobalParametersProperty
(
globParams
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
numRounding
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
minVertexDistance
));
globParams
.
getParameters
().
add
(
new
ParameterProperty
(
schematronFile
));
return
plan
;
}
private
DefaultParameter
getDefaultParameter
(
String
reqKey
,
Map
<
String
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
>
reqs
,
String
paramName
)
{
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
requirement
=
reqs
.
get
(
reqKey
);
if
(
requirement
!=
null
)
{
for
(
DefaultParameter
param
:
requirement
.
getDefaultParameter
())
{
if
(
param
.
getName
().
equals
(
paramName
))
{
return
param
;
}
}
}
return
null
;
}
private
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
createFilter
()
{
var
filter
=
new
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
();
handleInputFilter
(
filter
);
if
(
excludeFilters
!=
null
)
{
for
(
Filter
f
:
excludeFilters
)
{
if
(
f
instanceof
TypeFilter
tf
)
{
FeatureType
type
=
tf
.
getType
();
TopLevelFeatureType
tlft
=
mapToTopLevelFeatureType
(
type
);
if
(
tlft
==
null
)
{
continue
;
}
removeFilter
(
tlft
,
filter
);
}
}
}
return
filter
;
}
private
void
handleInputFilter
(
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
if
(
includeFilters
==
null
||
includeFilters
.
isEmpty
())
{
// no filter means, use all
addAllFilters
(
filter
);
}
else
{
for
(
Filter
f
:
includeFilters
)
{
if
(
f
instanceof
TypeFilter
tf
)
{
FeatureType
type
=
tf
.
getType
();
TopLevelFeatureType
tlft
=
mapToTopLevelFeatureType
(
type
);
if
(
tlft
==
null
)
{
continue
;
}
Checking
c
=
new
Checking
();
c
.
setFeatureType
(
tlft
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
c
));
}
}
if
(
filter
.
getChecking
().
isEmpty
())
{
// this happens if no type include filter was used
// it is possible only single objects were tested then
// so include everything
addAllFilters
(
filter
);
}
}
}
private
void
addAllFilters
(
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
Checking
buildingChecking
=
new
Checking
();
buildingChecking
.
setFeatureType
(
TopLevelFeatureType
.
BUILDING
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
buildingChecking
));
Checking
bridgeChecking
=
new
Checking
();
bridgeChecking
.
setFeatureType
(
TopLevelFeatureType
.
BRIDGE
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
bridgeChecking
));
Checking
landChecking
=
new
Checking
();
landChecking
.
setFeatureType
(
TopLevelFeatureType
.
LAND
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
landChecking
));
Checking
transportationChecking
=
new
Checking
();
transportationChecking
.
setFeatureType
(
TopLevelFeatureType
.
TRANSPORTATION
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
transportationChecking
));
Checking
vegetationChecking
=
new
Checking
();
vegetationChecking
.
setFeatureType
(
TopLevelFeatureType
.
VEGETATION
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
vegetationChecking
));
Checking
waterChecking
=
new
Checking
();
waterChecking
.
setFeatureType
(
TopLevelFeatureType
.
WATER
);
filter
.
getChecking
().
add
(
new
CheckingProperty
(
waterChecking
));
}
private
void
removeFilter
(
TopLevelFeatureType
tlft
,
de
.
hft
.
stuttgart
.
quality
.
model
.
types
.
Filter
filter
)
{
for
(
CheckingProperty
c
:
filter
.
getChecking
())
{
if
(
c
.
getObject
().
getFeatureType
().
equals
(
tlft
))
{
filter
.
getChecking
().
remove
(
c
);
return
;
}
}
}
private
TopLevelFeatureType
mapToTopLevelFeatureType
(
FeatureType
type
)
{
return
switch
(
type
)
{
case
BRIDGE
->
TopLevelFeatureType
.
BRIDGE
;
case
BUILDING
->
TopLevelFeatureType
.
BUILDING
;
...
...
@@ -400,298 +397,298 @@ public class Checker {
case
WATER
->
TopLevelFeatureType
.
WATER
;
default
->
null
;
};
}
private
RequirementId
mapToRequirement
(
String
requirementName
)
{
try
{
return
RequirementId
.
valueOf
(
requirementName
);
}
catch
(
IllegalArgumentException
e
)
{
return
null
;
}
}
public
ValidationConfiguration
getConfig
()
{
return
config
;
}
public
static
SvrlContentHandler
executeSchematronValidationIfAvailable
(
ValidationConfiguration
config
,
File
file
)
{
if
(
file
==
null
||
!
file
.
exists
())
{
return
null
;
}
try
{
return
executeSchematronValidationIfAvailable
(
config
,
new
FileInputStream
(
file
));
}
catch
(
FileNotFoundException
e
)
{
throw
new
UncheckedIOException
(
e
);
}
}
public
static
SvrlContentHandler
executeSchematronValidationIfAvailable
(
ValidationConfiguration
config
,
InputStream
in
)
{
if
(
config
.
getSchematronFilePath
()
!=
null
&&
!
config
.
getSchematronFilePath
().
isEmpty
())
{
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"Checker.schematronValidation"
));
}
try
{
TransformerFactory
transformerFactory
=
TransformerFactory
.
newInstance
(
"net.sf.saxon.TransformerFactoryImpl"
,
Checker
.
class
.
getClassLoader
());
transformerFactory
.
setAttribute
(
XMLConstants
.
ACCESS_EXTERNAL_DTD
,
""
);
transformerFactory
.
setFeature
(
XMLConstants
.
FEATURE_SECURE_PROCESSING
,
true
);
transformerFactory
.
setURIResolver
((
href
,
base
)
->
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
href
)));
Source
dsdlXslSource
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_dsdl_include.xsl"
));
Transformer
dsdlXslTransformer
=
transformerFactory
.
newTransformer
(
dsdlXslSource
);
DOMResult
dsdlXslResult
=
new
DOMResult
();
dsdlXslTransformer
.
transform
(
new
StreamSource
(
new
File
(
config
.
getSchematronFilePath
())),
dsdlXslResult
);
Source
abstractExpandXsl
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_abstract_expand.xsl"
));
Transformer
abstractExpandTransformer
=
transformerFactory
.
newTransformer
(
abstractExpandXsl
);
DOMResult
abstractExpandResult
=
new
DOMResult
();
abstractExpandTransformer
.
transform
(
new
DOMSource
(
dsdlXslResult
.
getNode
()),
abstractExpandResult
);
Source
svrlXslSource
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_svrl_for_xslt2.xsl"
));
Transformer
svrlTransformer
=
transformerFactory
.
newTransformer
(
svrlXslSource
);
DOMResult
schematronXsltResult
=
new
DOMResult
();
svrlTransformer
.
transform
(
new
DOMSource
(
abstractExpandResult
.
getNode
()),
schematronXsltResult
);
Transformer
schematronTransformer
=
transformerFactory
.
newTransformer
(
new
DOMSource
(
schematronXsltResult
.
getNode
()));
Source
cityGmlSource
=
new
StreamSource
(
in
);
SvrlContentHandler
handler
=
new
SvrlContentHandler
();
Result
finalResult
=
new
SAXResult
(
handler
);
schematronTransformer
.
transform
(
cityGmlSource
,
finalResult
);
return
handler
;
}
catch
(
TransformerException
e
)
{
logger
.
catching
(
e
);
}
}
return
null
;
}
private
void
buildFilters
()
{
FilterConfiguration
filterConfig
=
config
.
getFilter
();
if
(
filterConfig
==
null
)
{
includeFilters
=
Collections
.
emptyList
();
excludeFilters
=
Collections
.
emptyList
();
return
;
}
excludeFilters
=
buildExcludeFilters
(
filterConfig
);
includeFilters
=
buildIncludeFilters
(
filterConfig
);
}
private
List
<
Filter
>
buildExcludeFilters
(
FilterConfiguration
filterConfig
)
{
if
(
filterConfig
==
null
)
{
return
Collections
.
emptyList
();
}
ExcludeFilterConfiguration
excludeConfig
=
filterConfig
.
getExclude
();
if
(
excludeConfig
==
null
)
{
return
Collections
.
emptyList
();
}
else
{
List
<
Filter
>
filters
=
new
ArrayList
<>();
if
(
excludeConfig
.
getTypes
()
!=
null
)
{
for
(
FeatureType
excludeType
:
excludeConfig
.
getTypes
())
{
filters
.
add
(
new
TypeFilter
(
excludeType
));
}
}
if
(
excludeConfig
.
getIds
()
!=
null
)
{
for
(
String
excludePattern
:
excludeConfig
.
getIds
())
{
Filter
f
=
new
EqualsIgnoreCaseFilter
(
excludePattern
);
filters
.
add
(
f
);
}
}
return
filters
;
}
}
private
List
<
Filter
>
buildIncludeFilters
(
FilterConfiguration
filterConfig
)
{
if
(
filterConfig
==
null
)
{
return
Collections
.
emptyList
();
}
IncludeFilterConfiguration
includeConfig
=
filterConfig
.
getInclude
();
if
(
includeConfig
==
null
)
{
return
Collections
.
emptyList
();
}
else
{
List
<
Filter
>
filters
=
new
ArrayList
<>();
if
(
includeConfig
.
getTypes
()
!=
null
)
{
for
(
FeatureType
includeType
:
includeConfig
.
getTypes
())
{
filters
.
add
(
new
TypeFilter
(
includeType
));
}
}
if
(
includeConfig
.
getIds
()
!=
null
)
{
for
(
String
includePattern
:
includeConfig
.
getIds
())
{
Filter
f
=
new
EqualsIgnoreCaseFilter
(
includePattern
);
filters
.
add
(
f
);
}
}
return
filters
;
}
}
private
void
setValidationConfig
(
ValidationConfiguration
config
)
{
if
(
config
==
null
)
{
throw
new
IllegalArgumentException
(
"Validation configuration may not be null"
);
}
this
.
config
=
config
;
buildFilters
();
ParserConfiguration
parserConfig
=
config
.
getParserConfiguration
();
List
<
Check
>
checks
=
collectEnabledChecksAndInit
(
parserConfig
,
config
);
execLayers
=
buildExecutionLayers
(
checks
);
}
private
List
<
Check
>
collectEnabledChecksAndInit
(
ParserConfiguration
parserConfig
,
ValidationConfiguration
config
)
{
Set
<
CheckId
>
enabledCheck
=
new
HashSet
<>();
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
=
new
HashMap
<>();
for
(
Entry
<
String
,
RequirementConfiguration
>
e
:
config
.
getRequirements
().
entrySet
())
{
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
=
Checks
.
getAvailableRequirements
().
get
(
e
.
getKey
());
if
(
req
==
null
)
{
logger
.
warn
(
"Could not find any check that satisfies requirement {}, it will not be checked"
,
e
.
getKey
());
}
else
{
if
(
e
.
getValue
().
isEnabled
())
{
// this requirement is enabled
insertGlobalParameters
(
config
,
enabledCheck
,
parameterMap
,
e
,
req
);
}
}
}
fillParameterMapsWithDefaultParameter
(
enabledCheck
,
parameterMap
);
ArrayList
<
Check
>
checkList
=
new
ArrayList
<>();
for
(
CheckId
id
:
enabledCheck
)
{
Check
c
=
checkConfig
.
getCheckForId
(
id
);
c
.
init
(
parameterMap
.
get
(
id
),
parserConfig
);
checkList
.
add
(
c
);
}
return
checkList
;
}
private
void
insertGlobalParameters
(
ValidationConfiguration
config
,
Set
<
CheckId
>
enabledCheck
,
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
,
Entry
<
String
,
RequirementConfiguration
>
e
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
)
{
for
(
CheckPrototype
proto
:
Checks
.
getCheckPrototypes
())
{
if
(
proto
.
checksRequirements
().
contains
(
req
))
{
// this requirement is checked by this check
// put all requirement parameter in the map
parameterMap
.
compute
(
proto
.
getCheckId
(),
(
k
,
v
)
->
{
if
(
v
==
null
)
{
v
=
new
HashMap
<>();
v
.
put
(
GlobalParameters
.
NUMBER_OF_ROUNDING_PLACES
,
config
.
getNumberOfRoundingPlacesAsString
());
v
.
put
(
GlobalParameters
.
MIN_VERTEX_DISTANCE
,
config
.
getMinVertexDistanceAsString
());
}
v
.
putAll
(
e
.
getValue
().
getParameters
());
return
v
;
});
enabledCheck
.
add
(
proto
.
getCheckId
());
collectDependencyChecks
(
proto
,
enabledCheck
);
}
}
}
private
void
fillParameterMapsWithDefaultParameter
(
Set
<
CheckId
>
enabledCheck
,
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
)
{
for
(
CheckId
id
:
enabledCheck
)
{
CheckPrototype
proto
=
Checks
.
getCheckPrototypeForId
(
id
);
Map
<
String
,
String
>
map
=
parameterMap
.
computeIfAbsent
(
id
,
k
->
new
HashMap
<>());
for
(
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
:
proto
.
checksRequirements
())
{
if
(
proto
.
checksRequirements
().
contains
(
req
))
{
for
(
DefaultParameter
param
:
req
.
getDefaultParameter
())
{
map
.
computeIfAbsent
(
param
.
getName
(),
k
->
param
.
getValue
());
}
}
}
}
}
private
void
collectDependencyChecks
(
CheckPrototype
proto
,
Set
<
CheckId
>
enabledChecks
)
{
enabledChecks
.
addAll
(
proto
.
getDependencies
());
for
(
CheckId
id
:
proto
.
getDependencies
())
{
if
(
enabledChecks
.
contains
(
id
))
{
continue
;
}
CheckPrototype
depProto
=
Checks
.
getCheckPrototypeForId
(
id
);
collectDependencyChecks
(
depProto
,
enabledChecks
);
}
}
private
void
checkCityModel
(
CityDoctorModel
model
,
ProgressListener
l
)
{
Stream
<
CityObject
>
features
=
model
.
createFeatureStream
();
float
featureSum
=
model
.
getNumberOfFeatures
();
// stupid lamda with final variable restrictions
int
[]
currentFeature
=
new
int
[
1
];
features
.
forEach
(
co
->
{
if
(
config
.
getParserConfiguration
().
useLowMemoryConsumption
())
{
// no edges have been created yet, create them
co
.
prepareForChecking
();
}
// check every feature
executeChecksForCityObject
(
co
);
if
(
config
.
getParserConfiguration
().
useLowMemoryConsumption
())
{
// low memory consumption, remove edges again
co
.
clearMetaInformation
();
}
if
(
l
!=
null
)
{
currentFeature
[
0
]++;
l
.
updateProgress
(
currentFeature
[
0
]
/
featureSum
);
}
});
}
private
boolean
filterObject
(
CityObject
co
)
{
return
isObjectIncluded
(
co
,
includeFilters
,
excludeFilters
);
}
private
boolean
isObjectIncluded
(
CityObject
co
,
List
<
Filter
>
includeFilters
,
List
<
Filter
>
excludeFilters
)
{
if
(!
includeFilters
.
isEmpty
())
{
boolean
include
=
false
;
for
(
Filter
f
:
includeFilters
)
{
if
(
f
.
matches
(
co
))
{
include
=
true
;
break
;
}
}
if
(!
include
)
{
// not included, ignore
return
false
;
}
}
// check if object is excluded
for
(
Filter
f
:
excludeFilters
)
{
if
(
f
.
matches
(
co
))
{
// exclude object
return
false
;
}
}
return
true
;
}
/**
* Checks the city object if it has not been removed by the filters. The check
* result are stored into the city object itself.
*
* @param co the city object that is going to be checked
*/
private
void
executeChecksForCityObject
(
CityObject
co
)
{
if
(!
filterObject
(
co
))
{
return
;
}
executeChecksForCheckable
(
co
);
}
/**
* Executes all checks for the checkable. This will bypass the filters. This
* will clear the old check results
*
* @param co the checkable.
*/
public
void
executeChecksForCheckable
(
Checkable
co
)
{
// throw away old results
co
.
clearAllContainedCheckResults
();
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
Localization
.
getText
(
"Checker.checkFeature"
),
co
);
}
}
private
RequirementId
mapToRequirement
(
String
requirementName
)
{
try
{
return
RequirementId
.
valueOf
(
requirementName
);
}
catch
(
IllegalArgumentException
e
)
{
return
null
;
}
}
public
ValidationConfiguration
getConfig
()
{
return
config
;
}
public
static
SvrlContentHandler
executeSchematronValidationIfAvailable
(
ValidationConfiguration
config
,
File
file
)
{
if
(
file
==
null
||
!
file
.
exists
())
{
return
null
;
}
try
{
return
executeSchematronValidationIfAvailable
(
config
,
new
FileInputStream
(
file
));
}
catch
(
FileNotFoundException
e
)
{
throw
new
UncheckedIOException
(
e
);
}
}
public
static
SvrlContentHandler
executeSchematronValidationIfAvailable
(
ValidationConfiguration
config
,
InputStream
in
)
{
if
(
config
.
getSchematronFilePath
()
!=
null
&&
!
config
.
getSchematronFilePath
().
isEmpty
())
{
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
Localization
.
getText
(
"Checker.schematronValidation"
));
}
try
{
TransformerFactory
transformerFactory
=
TransformerFactory
.
newInstance
(
"net.sf.saxon.TransformerFactoryImpl"
,
Checker
.
class
.
getClassLoader
());
transformerFactory
.
setAttribute
(
XMLConstants
.
ACCESS_EXTERNAL_DTD
,
""
);
transformerFactory
.
setFeature
(
XMLConstants
.
FEATURE_SECURE_PROCESSING
,
true
);
transformerFactory
.
setURIResolver
((
href
,
base
)
->
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
href
)));
Source
dsdlXslSource
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_dsdl_include.xsl"
));
Transformer
dsdlXslTransformer
=
transformerFactory
.
newTransformer
(
dsdlXslSource
);
DOMResult
dsdlXslResult
=
new
DOMResult
();
dsdlXslTransformer
.
transform
(
new
StreamSource
(
new
File
(
config
.
getSchematronFilePath
())),
dsdlXslResult
);
Source
abstractExpandXsl
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_abstract_expand.xsl"
));
Transformer
abstractExpandTransformer
=
transformerFactory
.
newTransformer
(
abstractExpandXsl
);
DOMResult
abstractExpandResult
=
new
DOMResult
();
abstractExpandTransformer
.
transform
(
new
DOMSource
(
dsdlXslResult
.
getNode
()),
abstractExpandResult
);
Source
svrlXslSource
=
new
StreamSource
(
Checker
.
class
.
getResourceAsStream
(
"iso_svrl_for_xslt2.xsl"
));
Transformer
svrlTransformer
=
transformerFactory
.
newTransformer
(
svrlXslSource
);
DOMResult
schematronXsltResult
=
new
DOMResult
();
svrlTransformer
.
transform
(
new
DOMSource
(
abstractExpandResult
.
getNode
()),
schematronXsltResult
);
Transformer
schematronTransformer
=
transformerFactory
.
newTransformer
(
new
DOMSource
(
schematronXsltResult
.
getNode
()));
Source
cityGmlSource
=
new
StreamSource
(
in
);
SvrlContentHandler
handler
=
new
SvrlContentHandler
();
Result
finalResult
=
new
SAXResult
(
handler
);
schematronTransformer
.
transform
(
cityGmlSource
,
finalResult
);
return
handler
;
}
catch
(
TransformerException
e
)
{
logger
.
catching
(
e
);
}
}
return
null
;
}
private
void
buildFilters
()
{
FilterConfiguration
filterConfig
=
config
.
getFilter
();
if
(
filterConfig
==
null
)
{
includeFilters
=
Collections
.
emptyList
();
excludeFilters
=
Collections
.
emptyList
();
return
;
}
excludeFilters
=
buildExcludeFilters
(
filterConfig
);
includeFilters
=
buildIncludeFilters
(
filterConfig
);
}
private
List
<
Filter
>
buildExcludeFilters
(
FilterConfiguration
filterConfig
)
{
if
(
filterConfig
==
null
)
{
return
Collections
.
emptyList
();
}
ExcludeFilterConfiguration
excludeConfig
=
filterConfig
.
getExclude
();
if
(
excludeConfig
==
null
)
{
return
Collections
.
emptyList
();
}
else
{
List
<
Filter
>
filters
=
new
ArrayList
<>();
if
(
excludeConfig
.
getTypes
()
!=
null
)
{
for
(
FeatureType
excludeType
:
excludeConfig
.
getTypes
())
{
filters
.
add
(
new
TypeFilter
(
excludeType
));
}
}
if
(
excludeConfig
.
getIds
()
!=
null
)
{
for
(
String
excludePattern
:
excludeConfig
.
getIds
())
{
Filter
f
=
new
EqualsIgnoreCaseFilter
(
excludePattern
);
filters
.
add
(
f
);
}
}
return
filters
;
}
}
private
List
<
Filter
>
buildIncludeFilters
(
FilterConfiguration
filterConfig
)
{
if
(
filterConfig
==
null
)
{
return
Collections
.
emptyList
();
}
IncludeFilterConfiguration
includeConfig
=
filterConfig
.
getInclude
();
if
(
includeConfig
==
null
)
{
return
Collections
.
emptyList
();
}
else
{
List
<
Filter
>
filters
=
new
ArrayList
<>();
if
(
includeConfig
.
getTypes
()
!=
null
)
{
for
(
FeatureType
includeType
:
includeConfig
.
getTypes
())
{
filters
.
add
(
new
TypeFilter
(
includeType
));
}
}
if
(
includeConfig
.
getIds
()
!=
null
)
{
for
(
String
includePattern
:
includeConfig
.
getIds
())
{
Filter
f
=
new
EqualsIgnoreCaseFilter
(
includePattern
);
filters
.
add
(
f
);
}
}
return
filters
;
}
}
private
void
setValidationConfig
(
ValidationConfiguration
config
)
{
if
(
config
==
null
)
{
throw
new
IllegalArgumentException
(
"Validation configuration may not be null"
);
}
this
.
config
=
config
;
buildFilters
();
ParserConfiguration
parserConfig
=
config
.
getParserConfiguration
();
List
<
Check
>
checks
=
collectEnabledChecksAndInit
(
parserConfig
,
config
);
execLayers
=
buildExecutionLayers
(
checks
);
}
private
List
<
Check
>
collectEnabledChecksAndInit
(
ParserConfiguration
parserConfig
,
ValidationConfiguration
config
)
{
Set
<
CheckId
>
enabledCheck
=
new
HashSet
<>();
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
=
new
HashMap
<>();
for
(
Entry
<
String
,
RequirementConfiguration
>
e
:
config
.
getRequirements
().
entrySet
())
{
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
=
Checks
.
getAvailableRequirements
().
get
(
e
.
getKey
());
if
(
req
==
null
)
{
logger
.
warn
(
"Could not find any check that satisfies requirement {}, it will not be checked"
,
e
.
getKey
());
}
else
{
if
(
e
.
getValue
().
isEnabled
())
{
// this requirement is enabled
insertGlobalParameters
(
config
,
enabledCheck
,
parameterMap
,
e
,
req
);
}
}
}
fillParameterMapsWithDefaultParameter
(
enabledCheck
,
parameterMap
);
ArrayList
<
Check
>
checkList
=
new
ArrayList
<>();
for
(
CheckId
id
:
enabledCheck
)
{
Check
c
=
checkConfig
.
getCheckForId
(
id
);
c
.
init
(
parameterMap
.
get
(
id
),
parserConfig
);
checkList
.
add
(
c
);
}
return
checkList
;
}
private
void
insertGlobalParameters
(
ValidationConfiguration
config
,
Set
<
CheckId
>
enabledCheck
,
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
,
Entry
<
String
,
RequirementConfiguration
>
e
,
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
)
{
for
(
CheckPrototype
proto
:
Checks
.
getCheckPrototypes
())
{
if
(
proto
.
checksRequirements
().
contains
(
req
))
{
// this requirement is checked by this check
// put all requirement parameter in the map
parameterMap
.
compute
(
proto
.
getCheckId
(),
(
k
,
v
)
->
{
if
(
v
==
null
)
{
v
=
new
HashMap
<>();
v
.
put
(
GlobalParameters
.
NUMBER_OF_ROUNDING_PLACES
,
config
.
getNumberOfRoundingPlacesAsString
());
v
.
put
(
GlobalParameters
.
MIN_VERTEX_DISTANCE
,
config
.
getMinVertexDistanceAsString
());
}
v
.
putAll
(
e
.
getValue
().
getParameters
());
return
v
;
});
enabledCheck
.
add
(
proto
.
getCheckId
());
collectDependencyChecks
(
proto
,
enabledCheck
);
}
}
}
private
void
fillParameterMapsWithDefaultParameter
(
Set
<
CheckId
>
enabledCheck
,
Map
<
CheckId
,
Map
<
String
,
String
>>
parameterMap
)
{
for
(
CheckId
id
:
enabledCheck
)
{
CheckPrototype
proto
=
Checks
.
getCheckPrototypeForId
(
id
);
Map
<
String
,
String
>
map
=
parameterMap
.
computeIfAbsent
(
id
,
k
->
new
HashMap
<>());
for
(
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
req
:
proto
.
checksRequirements
())
{
if
(
proto
.
checksRequirements
().
contains
(
req
))
{
for
(
DefaultParameter
param
:
req
.
getDefaultParameter
())
{
map
.
computeIfAbsent
(
param
.
getName
(),
k
->
param
.
getValue
());
}
}
}
}
}
private
void
collectDependencyChecks
(
CheckPrototype
proto
,
Set
<
CheckId
>
enabledChecks
)
{
enabledChecks
.
addAll
(
proto
.
getDependencies
());
for
(
CheckId
id
:
proto
.
getDependencies
())
{
if
(
enabledChecks
.
contains
(
id
))
{
continue
;
}
CheckPrototype
depProto
=
Checks
.
getCheckPrototypeForId
(
id
);
collectDependencyChecks
(
depProto
,
enabledChecks
);
}
}
private
void
checkCityModel
(
CityDoctorModel
model
,
ProgressListener
l
)
{
Stream
<
CityObject
>
features
=
model
.
createFeatureStream
();
float
featureSum
=
model
.
getNumberOfFeatures
();
// stupid lamda with final variable restrictions
int
[]
currentFeature
=
new
int
[
1
];
features
.
forEach
(
co
->
{
if
(
config
.
getParserConfiguration
().
useLowMemoryConsumption
())
{
// no edges have been created yet, create them
co
.
prepareForChecking
();
}
// check every feature
executeChecksForCityObject
(
co
);
if
(
config
.
getParserConfiguration
().
useLowMemoryConsumption
())
{
// low memory consumption, remove edges again
co
.
clearMetaInformation
();
}
if
(
l
!=
null
)
{
currentFeature
[
0
]++;
l
.
updateProgress
(
currentFeature
[
0
]
/
featureSum
);
}
});
}
private
boolean
filterObject
(
CityObject
co
)
{
return
isObjectIncluded
(
co
,
includeFilters
,
excludeFilters
);
}
private
boolean
isObjectIncluded
(
CityObject
co
,
List
<
Filter
>
includeFilters
,
List
<
Filter
>
excludeFilters
)
{
if
(!
includeFilters
.
isEmpty
())
{
boolean
include
=
false
;
for
(
Filter
f
:
includeFilters
)
{
if
(
f
.
matches
(
co
))
{
include
=
true
;
break
;
}
}
if
(!
include
)
{
// not included, ignore
return
false
;
}
}
// check if object is excluded
for
(
Filter
f
:
excludeFilters
)
{
if
(
f
.
matches
(
co
))
{
// exclude object
return
false
;
}
}
return
true
;
}
/**
* Checks the city object if it has not been removed by the filters. The check
* result are stored into the city object itself.
*
* @param co the city object that is going to be checked
*/
private
void
executeChecksForCityObject
(
CityObject
co
)
{
if
(!
filterObject
(
co
))
{
return
;
}
executeChecksForCheckable
(
co
);
}
/**
* Executes all checks for the checkable. This will bypass the filters. This
* will clear the old check results
*
* @param co the checkable.
*/
public
void
executeChecksForCheckable
(
Checkable
co
)
{
// throw away old results
co
.
clearAllContainedCheckResults
();
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
Localization
.
getText
(
"Checker.checkFeature"
),
co
);
}
for
(
List
<
Check
>
execLayer
:
execLayers
)
{
for
(
Check
check
:
execLayer
)
{
if
(
logger
.
isTraceEnabled
())
{
...
...
@@ -700,162 +697,162 @@ public class Checker {
co
.
accept
(
check
);
}
}
}
public
static
List
<
List
<
Check
>>
buildExecutionLayers
(
List
<
Check
>
checks
)
{
List
<
List
<
Check
>>
result
=
new
ArrayList
<>();
Set
<
Check
>
availableChecks
=
new
HashSet
<>(
checks
);
Set
<
CheckId
>
usedChecks
=
new
HashSet
<>();
while
(!
availableChecks
.
isEmpty
())
{
List
<
Check
>
layer
=
new
ArrayList
<>();
Iterator
<
Check
>
iterator
=
availableChecks
.
iterator
();
while
(
iterator
.
hasNext
())
{
Check
c
=
iterator
.
next
();
boolean
hasUnusedDependency
=
searchForUnusedDependency
(
usedChecks
,
c
);
if
(!
hasUnusedDependency
)
{
iterator
.
remove
();
layer
.
add
(
new
CheckContainer
(
c
));
}
}
if
(
layer
.
isEmpty
())
{
throw
new
IllegalStateException
(
"There are checks that have dependencies that are not executed or are unknown, aborting"
);
}
result
.
add
(
layer
);
for
(
Check
c
:
layer
)
{
usedChecks
.
add
(
c
.
getCheckId
());
}
}
return
result
;
}
private
static
boolean
searchForUnusedDependency
(
Set
<
CheckId
>
usedChecks
,
Check
c
)
{
boolean
hasUnusedDependency
=
false
;
for
(
CheckId
id
:
c
.
getDependencies
())
{
if
(!
usedChecks
.
contains
(
id
))
{
hasUnusedDependency
=
true
;
break
;
}
}
return
hasUnusedDependency
;
}
public
static
void
streamCheck
(
CityGmlZipEntry
entry
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
try
(
BufferedOutputStream
xmlBos
=
getXmlOutputMaybe
(
xmlOutput
);
BufferedOutputStream
pdfBos
=
getPdfOutputMaybe
(
pdfOutput
))
{
Checker
c
=
new
Checker
(
config
,
null
);
String
fileName
=
entry
.
getFileName
();
// create reporter if available
XmlStreamReporter
xmlReporter
=
getXmlReporter
(
config
,
xmlBos
,
fileName
);
PdfStreamReporter
pdfReporter
=
getPdfReporter
(
config
,
pdfBos
,
fileName
);
// execute schematron first
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
entryFile
.
getInputStream
());
CityGmlConsumer
con
=
new
StreamCityGmlConsumer
(
c
,
xmlReporter
,
pdfReporter
,
handler
,
config
,
null
);
// parse and validate
CityGmlParser
.
streamCityGml
(
entry
,
config
.
getParserConfiguration
(),
con
,
outputFile
);
// write reports if available
writeReport
(
xmlReporter
);
writeReport
(
pdfReporter
);
}
}
catch
(
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failReports"
),
e
);
}
}
public
static
void
streamCheck
(
File
inputFile
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
streamCheck
(
inputFile
,
xmlOutput
,
pdfOutput
,
config
,
null
,
outputFile
);
}
public
static
void
streamCheck
(
File
inputFile
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
FeatureCheckedListener
l
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
try
(
BufferedOutputStream
xmlBos
=
getXmlOutputMaybe
(
xmlOutput
);
BufferedOutputStream
pdfBos
=
getPdfOutputMaybe
(
pdfOutput
))
{
Checker
c
=
new
Checker
(
config
,
null
);
String
fileName
=
inputFile
.
getName
();
// create reporter if available
XmlStreamReporter
xmlReporter
=
getXmlReporter
(
config
,
xmlBos
,
fileName
);
PdfStreamReporter
pdfReporter
=
getPdfReporter
(
config
,
pdfBos
,
fileName
);
// execute schematron first
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
inputFile
);
CityGmlConsumer
con
=
new
StreamCityGmlConsumer
(
c
,
xmlReporter
,
pdfReporter
,
handler
,
config
,
l
);
// parse and validate
CityGmlParser
.
streamCityGml
(
inputFile
.
getAbsolutePath
(),
config
.
getParserConfiguration
(),
con
,
outputFile
);
// write reports if available
writeReport
(
xmlReporter
);
writeReport
(
pdfReporter
);
}
catch
(
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failReports"
),
e
);
}
}
private
static
XmlStreamReporter
getXmlReporter
(
ValidationConfiguration
config
,
BufferedOutputStream
xmlBos
,
String
fileName
)
{
XmlStreamReporter
xmlReporter
;
if
(
xmlBos
!=
null
)
{
xmlReporter
=
new
XmlStreamReporter
(
xmlBos
,
fileName
,
config
);
}
else
{
xmlReporter
=
null
;
}
return
xmlReporter
;
}
private
static
PdfStreamReporter
getPdfReporter
(
ValidationConfiguration
config
,
BufferedOutputStream
pdfBos
,
String
fileName
)
{
PdfStreamReporter
pdfReporter
;
if
(
pdfBos
!=
null
)
{
pdfReporter
=
new
PdfStreamReporter
(
pdfBos
,
fileName
,
config
);
}
else
{
pdfReporter
=
null
;
}
return
pdfReporter
;
}
public
static
void
writeReport
(
StreamReporter
reporter
)
throws
CheckReportWriteException
{
if
(
reporter
!=
null
)
{
reporter
.
finishReport
();
}
}
public
static
BufferedOutputStream
getPdfOutputMaybe
(
String
pdfOutput
)
throws
FileNotFoundException
{
return
pdfOutput
!=
null
?
new
BufferedOutputStream
(
new
FileOutputStream
(
pdfOutput
))
:
null
;
}
public
static
BufferedOutputStream
getXmlOutputMaybe
(
String
xmlOutput
)
throws
FileNotFoundException
{
return
xmlOutput
!=
null
?
new
BufferedOutputStream
(
new
FileOutputStream
(
xmlOutput
))
:
null
;
}
/**
* Checks the city object and writes report information into reporters. Clears
* old check results. If the city object would be filtered by the configured
* filters it is ignored and old check results are not cleared.
*
* @param xmlReporter a xml reporter
* @param pdfReporter a pdf reporter
* @param co the city object to be checked
*/
public
void
checkFeature
(
XmlStreamReporter
xmlReporter
,
PdfStreamReporter
pdfReporter
,
CityObject
co
)
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
Localization
.
getText
(
"Checker.checkFeature"
),
co
);
}
executeChecksForCityObject
(
co
);
if
(
xmlReporter
!=
null
)
{
xmlReporter
.
report
(
co
);
}
if
(
pdfReporter
!=
null
)
{
pdfReporter
.
report
(
co
);
}
}
}
public
static
List
<
List
<
Check
>>
buildExecutionLayers
(
List
<
Check
>
checks
)
{
List
<
List
<
Check
>>
result
=
new
ArrayList
<>();
Set
<
Check
>
availableChecks
=
new
HashSet
<>(
checks
);
Set
<
CheckId
>
usedChecks
=
new
HashSet
<>();
while
(!
availableChecks
.
isEmpty
())
{
List
<
Check
>
layer
=
new
ArrayList
<>();
Iterator
<
Check
>
iterator
=
availableChecks
.
iterator
();
while
(
iterator
.
hasNext
())
{
Check
c
=
iterator
.
next
();
boolean
hasUnusedDependency
=
searchForUnusedDependency
(
usedChecks
,
c
);
if
(!
hasUnusedDependency
)
{
iterator
.
remove
();
layer
.
add
(
new
CheckContainer
(
c
));
}
}
if
(
layer
.
isEmpty
())
{
throw
new
IllegalStateException
(
"There are checks that have dependencies that are not executed or are unknown, aborting"
);
}
result
.
add
(
layer
);
for
(
Check
c
:
layer
)
{
usedChecks
.
add
(
c
.
getCheckId
());
}
}
return
result
;
}
private
static
boolean
searchForUnusedDependency
(
Set
<
CheckId
>
usedChecks
,
Check
c
)
{
boolean
hasUnusedDependency
=
false
;
for
(
CheckId
id
:
c
.
getDependencies
())
{
if
(!
usedChecks
.
contains
(
id
))
{
hasUnusedDependency
=
true
;
break
;
}
}
return
hasUnusedDependency
;
}
public
static
void
streamCheck
(
CityGmlZipEntry
entry
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
try
(
BufferedOutputStream
xmlBos
=
getXmlOutputMaybe
(
xmlOutput
);
BufferedOutputStream
pdfBos
=
getPdfOutputMaybe
(
pdfOutput
))
{
Checker
c
=
new
Checker
(
config
,
null
);
String
fileName
=
entry
.
getFileName
();
// create reporter if available
XmlStreamReporter
xmlReporter
=
getXmlReporter
(
config
,
xmlBos
,
fileName
);
PdfStreamReporter
pdfReporter
=
getPdfReporter
(
config
,
pdfBos
,
fileName
);
// execute schematron first
try
(
CityGmlZipEntryFile
entryFile
=
new
CityGmlZipEntryFile
(
entry
))
{
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
entryFile
.
getInputStream
());
CityGmlConsumer
con
=
new
StreamCityGmlConsumer
(
c
,
xmlReporter
,
pdfReporter
,
handler
,
config
,
null
);
// parse and validate
CityGmlParser
.
streamCityGml
(
entry
,
config
.
getParserConfiguration
(),
con
,
outputFile
);
// write reports if available
writeReport
(
xmlReporter
);
writeReport
(
pdfReporter
);
}
}
catch
(
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failReports"
),
e
);
}
}
public
static
void
streamCheck
(
File
inputFile
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
streamCheck
(
inputFile
,
xmlOutput
,
pdfOutput
,
config
,
null
,
outputFile
);
}
public
static
void
streamCheck
(
File
inputFile
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
,
FeatureCheckedListener
l
,
String
outputFile
)
throws
IOException
,
CityGmlParseException
{
try
(
BufferedOutputStream
xmlBos
=
getXmlOutputMaybe
(
xmlOutput
);
BufferedOutputStream
pdfBos
=
getPdfOutputMaybe
(
pdfOutput
))
{
Checker
c
=
new
Checker
(
config
,
null
);
String
fileName
=
inputFile
.
getName
();
// create reporter if available
XmlStreamReporter
xmlReporter
=
getXmlReporter
(
config
,
xmlBos
,
fileName
);
PdfStreamReporter
pdfReporter
=
getPdfReporter
(
config
,
pdfBos
,
fileName
);
// execute schematron first
SvrlContentHandler
handler
=
executeSchematronValidationIfAvailable
(
config
,
inputFile
);
CityGmlConsumer
con
=
new
StreamCityGmlConsumer
(
c
,
xmlReporter
,
pdfReporter
,
handler
,
config
,
l
);
// parse and validate
CityGmlParser
.
streamCityGml
(
inputFile
.
getAbsolutePath
(),
config
.
getParserConfiguration
(),
con
,
outputFile
);
// write reports if available
writeReport
(
xmlReporter
);
writeReport
(
pdfReporter
);
}
catch
(
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failReports"
),
e
);
}
}
private
static
XmlStreamReporter
getXmlReporter
(
ValidationConfiguration
config
,
BufferedOutputStream
xmlBos
,
String
fileName
)
{
XmlStreamReporter
xmlReporter
;
if
(
xmlBos
!=
null
)
{
xmlReporter
=
new
XmlStreamReporter
(
xmlBos
,
fileName
,
config
);
}
else
{
xmlReporter
=
null
;
}
return
xmlReporter
;
}
private
static
PdfStreamReporter
getPdfReporter
(
ValidationConfiguration
config
,
BufferedOutputStream
pdfBos
,
String
fileName
)
{
PdfStreamReporter
pdfReporter
;
if
(
pdfBos
!=
null
)
{
pdfReporter
=
new
PdfStreamReporter
(
pdfBos
,
fileName
,
config
);
}
else
{
pdfReporter
=
null
;
}
return
pdfReporter
;
}
public
static
void
writeReport
(
StreamReporter
reporter
)
throws
CheckReportWriteException
{
if
(
reporter
!=
null
)
{
reporter
.
finishReport
();
}
}
public
static
BufferedOutputStream
getPdfOutputMaybe
(
String
pdfOutput
)
throws
FileNotFoundException
{
return
pdfOutput
!=
null
?
new
BufferedOutputStream
(
new
FileOutputStream
(
pdfOutput
))
:
null
;
}
public
static
BufferedOutputStream
getXmlOutputMaybe
(
String
xmlOutput
)
throws
FileNotFoundException
{
return
xmlOutput
!=
null
?
new
BufferedOutputStream
(
new
FileOutputStream
(
xmlOutput
))
:
null
;
}
/**
* Checks the city object and writes report information into reporters. Clears
* old check results. If the city object would be filtered by the configured
* filters it is ignored and old check results are not cleared.
*
* @param xmlReporter a xml reporter
* @param pdfReporter a pdf reporter
* @param co the city object to be checked
*/
public
void
checkFeature
(
XmlStreamReporter
xmlReporter
,
PdfStreamReporter
pdfReporter
,
CityObject
co
)
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
Localization
.
getText
(
"Checker.checkFeature"
),
co
);
}
executeChecksForCityObject
(
co
);
if
(
xmlReporter
!=
null
)
{
xmlReporter
.
report
(
co
);
}
if
(
pdfReporter
!=
null
)
{
pdfReporter
.
report
(
co
);
}
}
}
This diff is collapsed.
Click to expand it.
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/check/CheckerTest.java
+
87
-
90
View file @
671c277b
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
...
...
@@ -18,16 +18,6 @@
*/
package
de.hft.stuttgart.citydoctor2.check
;
import
java.io.File
;
import
java.io.IOException
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.TemporaryFolder
;
import
de.hft.stuttgart.citydoctor2.CityDoctorValidation
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
...
...
@@ -35,99 +25,106 @@ import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive
;
import
de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.TemporaryFolder
;
import
java.io.File
;
import
java.io.IOException
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
*
* @author Matthias Betz
*
*/
public
class
CheckerTest
{
@Rule
public
TemporaryFolder
folder
=
new
TemporaryFolder
();
@Rule
public
TemporaryFolder
folder
=
new
TemporaryFolder
();
@Test
public
void
testSchematron
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
config
.
getRequirements
().
get
(
Requirement
.
R_SE_BS_ROOF_UNFRAGMENTED
.
toString
()).
setEnabled
(
false
);
config
.
setSchematronFilePathInGlobalParameters
(
"src/test/resources/schematronTest.xml"
);
CityDoctorModel
model
=
CityGmlParser
.
parseCityGmlFile
(
"src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml"
,
config
.
getParserConfiguration
());
Checker
checker
=
new
Checker
(
config
,
model
);
checker
.
runChecks
();
for
(
Building
b
:
model
.
getBuildings
())
{
if
(
b
.
getGmlId
().
getGmlString
().
equals
(
"_Simple_BD.1"
))
{
assertTrue
(
b
.
containsAnyError
());
}
else
{
assertFalse
(
b
.
containsAnyError
());
}
}
assertFalse
(
model
.
getGlobalErrors
().
isEmpty
());
}
@Test
public
void
testSchematron
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
config
.
getRequirements
().
get
(
Requirement
.
R_SE_BS_ROOF_UNFRAGMENTED
.
toString
()).
setEnabled
(
false
);
config
.
setSchematronFilePathInGlobalParameters
(
"src/test/resources/schematronTest.xml"
);
CityDoctorModel
model
=
CityGmlParser
.
parseCityGmlFile
(
"src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml"
,
config
.
getParserConfiguration
());
Checker
checker
=
new
Checker
(
config
,
model
);
checker
.
runChecks
();
for
(
Building
b
:
model
.
getBuildings
())
{
if
(
b
.
getGmlId
().
getGmlString
().
equals
(
"_Simple_BD.1"
))
{
assertTrue
(
b
.
containsAnyError
());
}
else
{
assertFalse
(
b
.
containsAnyError
());
}
}
assertFalse
(
model
.
getGlobalErrors
().
isEmpty
());
}
@Test
public
void
testChecker
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
@Test
public
void
testChecker
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
File
f
=
folder
.
newFile
();
File
f2
=
folder
.
newFile
();
try
{
String
[]
args
=
new
String
[
6
];
args
[
0
]
=
"-in"
;
args
[
1
]
=
"src/test/resources/QA-CS-CONCOMP.gml"
;
args
[
2
]
=
"-xmlReport"
;
args
[
3
]
=
f
.
getAbsolutePath
();
args
[
4
]
=
"-pdfReport"
;
args
[
5
]
=
f2
.
getAbsolutePath
();
CityDoctorValidation
.
main
(
args
);
assertTrue
(
f
.
exists
());
assertTrue
(
f2
.
exists
());
}
finally
{
f
.
delete
();
f2
.
delete
();
}
}
File
f
=
folder
.
newFile
();
File
f2
=
folder
.
newFile
();
try
{
String
[]
args
=
new
String
[
6
];
args
[
0
]
=
"-in"
;
args
[
1
]
=
"src/test/resources/QA-CS-CONCOMP.gml"
;
args
[
2
]
=
"-xmlReport"
;
args
[
3
]
=
f
.
getAbsolutePath
();
args
[
4
]
=
"-pdfReport"
;
args
[
5
]
=
f2
.
getAbsolutePath
();
CityDoctorValidation
.
main
(
args
);
assertTrue
(
f
.
exists
());
assertTrue
(
f2
.
exists
());
}
finally
{
f
.
delete
();
f2
.
delete
();
}
}
@Test
public
void
testStreaming
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
File
f
=
folder
.
newFile
();
File
f2
=
folder
.
newFile
();
File
f3
=
folder
.
newFile
();
try
{
String
[]
args
=
new
String
[
10
];
args
[
0
]
=
"-in"
;
args
[
1
]
=
"src/test/resources/testarea.gml"
;
args
[
2
]
=
"-config"
;
args
[
3
]
=
"src/test/resources/testConfigWithStreaming.yml"
;
args
[
4
]
=
"-pdfReport"
;
args
[
5
]
=
f
.
getAbsolutePath
();
args
[
6
]
=
"-xmlReport"
;
args
[
7
]
=
f2
.
getAbsolutePath
();
args
[
8
]
=
"-out"
;
args
[
9
]
=
f3
.
getAbsolutePath
();
CityDoctorValidation
.
main
(
args
);
assertTrue
(
f
.
exists
());
assertTrue
(
f2
.
exists
());
assertTrue
(
f3
.
exists
());
}
finally
{
f
.
delete
();
f2
.
delete
();
f3
.
delete
();
}
}
@Test
public
void
testStreaming
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
File
f
=
folder
.
newFile
();
File
f2
=
folder
.
newFile
();
File
f3
=
folder
.
newFile
();
try
{
String
[]
args
=
new
String
[
10
];
args
[
0
]
=
"-in"
;
args
[
1
]
=
"src/test/resources/testarea.gml"
;
args
[
2
]
=
"-config"
;
args
[
3
]
=
"src/test/resources/testConfigWithStreaming.yml"
;
args
[
4
]
=
"-pdfReport"
;
args
[
5
]
=
f
.
getAbsolutePath
();
args
[
6
]
=
"-xmlReport"
;
args
[
7
]
=
f2
.
getAbsolutePath
();
args
[
8
]
=
"-out"
;
args
[
9
]
=
f3
.
getAbsolutePath
();
CityDoctorValidation
.
main
(
args
);
assertTrue
(
f
.
exists
());
assertTrue
(
f2
.
exists
());
assertTrue
(
f3
.
exists
());
}
finally
{
f
.
delete
();
f2
.
delete
();
f3
.
delete
();
}
}
@Test
public
void
testZipEntryChecking
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
CityGmlZipArchive
cgmlArch
=
CityGmlZipArchive
.
register
(
"src/test/resources/zipArchive.zip"
);
assertNotNull
(
cgmlArch
);
cgmlArch
.
mountArchive
(
new
ParserConfiguration
(
8
,
false
));
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
for
(
CityGmlZipEntry
entry
:
cgmlArch
.
getEntries
()){
Checker
.
streamCheck
(
entry
,
null
,
null
,
config
,
null
);
}
}
@Test
public
void
testZipEntryChecking
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
CityGmlZipArchive
cgmlArch
=
CityGmlZipArchive
.
register
(
"src/test/resources/zipArchive.zip"
);
assertNotNull
(
cgmlArch
);
cgmlArch
.
mountArchive
(
new
ParserConfiguration
(
8
,
false
));
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
for
(
CityGmlZipEntry
entry
:
cgmlArch
.
getEntries
())
{
Checker
.
streamCheck
(
entry
,
null
,
null
,
config
,
null
);
}
}
}
This diff is collapsed.
Click to expand it.
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