Skip to content

Commit

Permalink
Merge pull request #184 from 3dcitydb/ade-properties-fix
Browse files Browse the repository at this point in the history
Fix export of ADE properties for ADE features directly derived from AbstractCityObject
  • Loading branch information
Zhihang Yao authored Apr 23, 2021
2 parents c781845 + 1b812ec commit c754796
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 22 deletions.
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

0 comments on commit c754796

Please sign in to comment.