Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix export of ADE properties for ADE features directly derived from AbstractCityObject #184

Merged
merged 2 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected List<Table> addJoinsToADEHookTables(TableEnum type, Table fromTable) {
List<Table> tables = null;
if (exporter.hasADESupport()) {
Set<String> tableNames = exporter.getADEHookTables(type);
if (tableNames != null) {
if (!tableNames.isEmpty()) {
tables = new ArrayList<>();
for (String tableName : tableNames) {
Table table = new Table(tableName, exporter.getDatabaseAdapter().getConnectionDetails().getSchema());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -887,29 +887,32 @@ public void close() throws CityGMLExportException, SQLException {
}

protected Set<String> getADEHookTables(TableEnum table) {
Set<String> adeHookTables = null;
Set<String> adeHookTables = new HashSet<>();

for (FeatureType featureType : schemaMapping.listFeatureTypesByTable(table.getName(), true)) {
// skip ADE features - we do not support ADEs of ADEs
if (adeManager.getExtensionByObjectClassId(featureType.getObjectClassId()) != null) {
continue;
}

for (AbstractProperty property : featureType.listProperties(false, true)) {
if (property instanceof InjectedProperty) {
String adeHookTable = ((InjectedProperty) property).getBaseJoin().getTable();
adeHookTables.addAll(getADEHookTables(featureType));
}

ADEExtension extension = adeManager.getExtensionByTableName(adeHookTable);
if (extension == null || !extension.isEnabled()) {
continue;
}
return adeHookTables;
}

if (adeHookTables == null) {
adeHookTables = new HashSet<>();
}
protected Set<String> getADEHookTables(FeatureType featureType) {
Set<String> adeHookTables = new HashSet<>();
for (AbstractProperty property : featureType.listProperties(false, true)) {
if (property instanceof InjectedProperty) {
String adeHookTable = ((InjectedProperty) property).getBaseJoin().getTable();

adeHookTables.add(adeHookTable);
ADEExtension extension = adeManager.getExtensionByTableName(adeHookTable);
if (extension == null || !extension.isEnabled()) {
continue;
}

adeHookTables.add(adeHookTable);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.citydb.database.schema.TableEnum;
import org.citydb.database.schema.mapping.AbstractObjectType;
import org.citydb.database.schema.mapping.FeatureType;
import org.citydb.database.schema.mapping.MappingConstants;
import org.citydb.query.Query;
import org.citydb.query.filter.projection.ProjectionFilter;
import org.citydb.query.filter.tiling.Tile;
Expand All @@ -54,6 +55,7 @@
import org.citydb.sqlbuilder.select.operator.comparison.ComparisonFactory;
import org.citydb.sqlbuilder.select.operator.comparison.ComparisonName;
import org.citygml4j.geometry.Point;
import org.citygml4j.model.citygml.ade.binding.ADEModelObject;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.core.ExternalObject;
import org.citygml4j.model.citygml.core.ExternalReference;
Expand Down Expand Up @@ -86,9 +88,9 @@
import java.util.Map;
import java.util.Set;

public class DBCityObject implements DBExporter {
public class DBCityObject extends AbstractTypeExporter {
private final Query query;
private final CityGMLExportManager exporter;
private final Connection connection;
private final PreparedStatement psSelect;
private final PreparedStatement psBulk;
private final Map<Long, List<ObjectContext>> batches;
Expand All @@ -105,15 +107,18 @@ public class DBCityObject implements DBExporter {
private final String appearanceModule;
private final String gmlModule;

private Map<Integer, List<Table>> adeHookTables;
private Map<Integer, PreparedStatement> adeHookStatements;
private DBLocalAppearance appearanceExporter;
private boolean setTileInfoAsGenericAttribute;
private Tile activeTile;
private SimpleTilingOptions tilingOptions;
private String cityDBADEModule;

public DBCityObject(Connection connection, Query query, CityGMLExportManager exporter) throws CityGMLExportException, SQLException {
super(exporter);
this.query = query;
this.exporter = exporter;
this.connection = connection;

batches = new LinkedHashMap<>();
batchSize = exporter.getFeatureBatchSize();
Expand Down Expand Up @@ -144,12 +149,12 @@ public DBCityObject(Connection connection, Query query, CityGMLExportManager exp
gmlModule = GMLCoreModule.v3_1_1.getNamespaceURI();
String schema = exporter.getDatabaseAdapter().getConnectionDetails().getSchema();

Table table = new Table(TableEnum.CITYOBJECT.getName(), schema);
table = new Table(TableEnum.CITYOBJECT.getName(), schema);
Table externalReference = new Table(TableEnum.EXTERNAL_REFERENCE.getName(), schema);
Table generalization = new Table(TableEnum.GENERALIZATION.getName(), schema);
Table genericAttributes = new Table(TableEnum.CITYOBJECT_GENERICATTRIB.getName(), schema);

Select select = new Select().addProjection(table.getColumn("id"), table.getColumn("gmlid"), exporter.getGeometryColumn(table.getColumn("envelope")),
select = new Select().addProjection(table.getColumn("id"), table.getColumn("gmlid"), exporter.getGeometryColumn(table.getColumn("envelope")),
table.getColumn("name"), table.getColumn("name_codespace"), table.getColumn("description"), table.getColumn("creation_date"),
table.getColumn("termination_date"), table.getColumn("relative_to_terrain"), table.getColumn("relative_to_water"),
externalReference.getColumn("id", "exid"), externalReference.getColumn("infosys"), externalReference.getColumn("name", "exname"), externalReference.getColumn("uri"),
Expand All @@ -174,13 +179,16 @@ public DBCityObject(Connection connection, Query query, CityGMLExportManager exp
}

protected void addBatch(AbstractGML object, long objectId, AbstractObjectType<?> objectType, ProjectionFilter projectionFilter) throws CityGMLExportException, SQLException {
batches.computeIfAbsent(objectId, v -> new ArrayList<>()).add(new ObjectContext(object, objectType, projectionFilter));
ObjectContext context = new ObjectContext(object, objectType, projectionFilter);
batches.computeIfAbsent(objectId, v -> new ArrayList<>()).add(context);
if (batches.size() == batchSize)
executeBatch();

// ADE-specific extensions
if (exporter.hasADESupport())
if (exporter.hasADESupport()) {
exporter.delegateToADEExporter(object, objectId, objectType, projectionFilter);
delegateADEProperties(context, objectId);
}
}

public boolean executeBatch() throws CityGMLExportException, SQLException {
Expand Down Expand Up @@ -261,14 +269,16 @@ private boolean doExport(long objectId, ObjectContext context) throws CityGMLExp
postprocess();

// ADE-specific extensions
if (exporter.hasADESupport())
if (exporter.hasADESupport()) {
exporter.delegateToADEExporter(context.object, objectId, context.objectType, context.projectionFilter);
delegateADEProperties(context, objectId);
}

return true;
}
}

protected boolean initializeObject(ObjectContext context, ResultSet rs) throws CityGMLExportException, SQLException {
private boolean initializeObject(ObjectContext context, ResultSet rs) throws SQLException {
boolean setEnvelope = !context.isCityObject || (context.projectionFilter.containsProperty("boundedBy", gmlModule)
&& (exporter.getExportConfig().getGeneralOptions().getEnvelope().getFeatureMode() == FeatureEnvelopeMode.ALL
|| (exporter.getExportConfig().getGeneralOptions().getEnvelope().getFeatureMode() == FeatureEnvelopeMode.TOP_LEVEL && context.isTopLevel)));
Expand Down Expand Up @@ -472,10 +482,79 @@ private void postprocess() throws CityGMLExportException, SQLException {
generalizesToExporter.executeBatch();
}

private void delegateADEProperties(ObjectContext context, long objectId) throws SQLException, CityGMLExportException {
// we only have to query and delegate ADE properties here if the
// ADE feature is a direct child of AbstractCityObject or AbstractSite
// and, thus, is not handled by another exporter class
if (context.queryADEHookTables) {
List<Table> adeHookTables = getADEHookTables(context);
if (adeHookTables.isEmpty()) {
return;
}

PreparedStatement ps = getADEHookStatement(context, adeHookTables);
ps.setLong(1, objectId);

try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
List<String> tableNames = retrieveADEHookTables(adeHookTables, rs);
if (tableNames != null) {
exporter.delegateToADEExporter(tableNames, (AbstractFeature) context.object, objectId,
(FeatureType) context.objectType, context.projectionFilter);
}
}
}
}
}

private List<Table> getADEHookTables(ObjectContext context) {
if (adeHookTables == null) {
adeHookTables = new HashMap<>();
}

List<Table> tables = adeHookTables.get(context.objectType.getObjectClassId());
if (tables == null) {
tables = new ArrayList<>();
for (String tableName : exporter.getADEHookTables((FeatureType) context.objectType)) {
tables.add(new Table(tableName, exporter.getDatabaseAdapter().getConnectionDetails().getSchema()));
}

adeHookTables.put(context.objectType.getObjectClassId(), tables);
}

return tables;
}

private PreparedStatement getADEHookStatement(ObjectContext context, List<Table> adeHookTables) throws SQLException {
if (adeHookStatements == null) {
adeHookStatements = new HashMap<>();
}

PreparedStatement ps = adeHookStatements.get(context.objectType.getObjectClassId());
if (ps == null) {
Select select = new Select().addSelection(ComparisonFactory.equalTo(table.getColumn("id"), new PlaceHolder<>()));
for (Table adeHookTable : adeHookTables) {
select.addProjection(adeHookTable.getColumn("id", adeHookTable.getAlias() + adeHookTable.getName()))
.addJoin(JoinFactory.left(adeHookTable, "id", ComparisonName.EQUAL_TO, table.getColumn("id")));
}

ps = connection.prepareStatement(select.toString());
adeHookStatements.put(context.objectType.getObjectClassId(), ps);
}

return ps;
}

@Override
public void close() throws SQLException {
psBulk.close();
psSelect.close();

if (adeHookStatements != null) {
for (PreparedStatement ps : adeHookStatements.values()) {
ps.close();
}
}
}

private static class ObjectContext {
Expand All @@ -486,6 +565,7 @@ private static class ObjectContext {
final boolean isCityObject;
final boolean isTopLevel;

boolean queryADEHookTables;
boolean isInitialized;
Set<Long> appearances;
Set<Long> generalizesTos;
Expand All @@ -508,6 +588,12 @@ private static class ObjectContext {
externalReferences = new HashSet<>();
genericAttributes = new HashSet<>();
genericAttributeSets = new HashMap<>();

if (object instanceof ADEModelObject
&& objectType.isSetExtension()
&& objectType.getExtension().getBase().getTable().equals(MappingConstants.CITYOBJECT)) {
queryADEHookTables = true;
}
}
}

Expand Down