Skip to content

Commit 5a38db8

Browse files
committed
Added json header to the spatial index. Header is used to configure kyro with geometrySerde.
1 parent 1c904b5 commit 5a38db8

File tree

7 files changed

+86
-20
lines changed

7 files changed

+86
-20
lines changed

jena-arq/src/main/java/org/apache/jena/system/TxnCtl.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
/**
2727
* Txn variant for use with try-with-resources. Allows raising
2828
* checked exceptions in an idiomatic way. Closing the TxnCtl
29-
* instance will by default abort the transaction unless it
29+
* instance will abort the transaction unless it
3030
* has been manually committed.
3131
* <p>
3232
*
@@ -35,15 +35,14 @@
3535
* public void myMethod() throws IOException {
3636
* try (TxnCtl txn = TxnCtl.begin(dataset, TxnType.WRITE)) {
3737
* // Do work
38+
* if (someError) {
39+
* throw new IOException();
40+
* }
3841
* // Must manually call commit on success.
3942
* txn.commit();
4043
* }
4144
* }
4245
* </pre>
43-
*
44-
* @param txn The transactional.
45-
* @param txnType The transaction type.
46-
* @return An instance of AutoCloseable that commits the transaction on success.
4746
*/
4847
public class TxnCtl
4948
implements AutoCloseable

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/index/v2/SpatialIndexIoKryo.java

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import java.io.IOException;
2121
import java.io.OutputStream;
2222
import java.lang.invoke.MethodHandles;
23+
import java.lang.reflect.InvocationTargetException;
2324
import java.nio.file.Files;
2425
import java.nio.file.Path;
2526
import java.util.Map;
27+
import java.util.Objects;
2628

2729
import org.apache.jena.atlas.RuntimeIOException;
2830
import org.apache.jena.atlas.io.IOX;
@@ -31,6 +33,8 @@
3133
import org.apache.jena.geosparql.implementation.registry.SRSRegistry;
3234
import org.apache.jena.geosparql.implementation.vocabulary.SRS_URI;
3335
import org.apache.jena.geosparql.spatial.SpatialIndexException;
36+
import org.apache.jena.geosparql.spatial.serde.GeometrySerdeAdapter;
37+
import org.apache.jena.geosparql.spatial.serde.GeometrySerdeAdapterJtsWkb;
3438
import org.apache.jena.geosparql.spatial.serde.JtsKryoRegistrator;
3539
import org.apache.jena.graph.Node;
3640
import org.apache.jena.query.Dataset;
@@ -41,6 +45,8 @@
4145
import com.esotericsoftware.kryo.Kryo;
4246
import com.esotericsoftware.kryo.io.Input;
4347
import com.esotericsoftware.kryo.io.Output;
48+
import com.google.gson.Gson;
49+
import com.google.gson.JsonObject;
4450

4551
public class SpatialIndexIoKryo {
4652
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -137,20 +143,42 @@ public static final void save(Path spatialIndexFile, SpatialIndexPerGraph index)
137143
* @param index spatial index
138144
*/
139145
public static void writeToOutputStream(OutputStream os, SpatialIndexPerGraph index) {
146+
GeometrySerdeAdapter geometrySerde = new GeometrySerdeAdapterJtsWkb();
147+
148+
JsonObject header = new JsonObject();
149+
header.addProperty("type", "jena-spatial-index");
150+
header.addProperty("version", "2.0.0");
151+
header.addProperty("geometrySerde", geometrySerde.getClass().getName());
152+
140153
Kryo kryo = new Kryo();
141-
JtsKryoRegistrator.registerClasses(kryo);
154+
JtsKryoRegistrator.registerClasses(kryo, geometrySerde);
142155
try (Output output = new Output(os)) {
156+
writeJson(output, header);
143157
writeIndex(kryo, output, index);
144158
output.flush();
145159
}
146160
}
147161

162+
public static void writeJson(Output output, JsonObject header) {
163+
Gson gson = new Gson();
164+
String headerStr = gson.toJson(header);
165+
output.writeString(headerStr);
166+
}
167+
148168
public static void writeIndex(Kryo kryo, Output output, SpatialIndexPerGraph index) {
149169
kryo.writeObject(output, index.getSrsInfo().getSrsURI());
150170
kryo.writeObject(output, index.getIndex().getDefaultTree());
151171
kryo.writeClassAndObject(output, index.getIndex().getNamedTreeMap());
152172
}
153173

174+
/** Read a string from input and return it as JSON. */
175+
public static JsonObject readHeader(Input input) {
176+
String headerStr = input.readString();
177+
Gson gson = new Gson();
178+
JsonObject obj = gson.fromJson(headerStr, JsonObject.class);
179+
return obj;
180+
}
181+
154182
/**
155183
* Load a SpatialIndex from file.<br>
156184
* Index will be built and empty if file does not exist or is null.
@@ -160,9 +188,6 @@ public static void writeIndex(Kryo kryo, Output output, SpatialIndexPerGraph ind
160188
* @throws SpatialIndexException
161189
*/
162190
public static final SpatialIndexPerGraph load(Path spatialIndexFile) throws SpatialIndexException {
163-
Kryo kryo = new Kryo();
164-
JtsKryoRegistrator.registerClasses(kryo);
165-
166191
String srsUri;
167192
STRtreePerGraph index;
168193

@@ -171,6 +196,33 @@ public static final SpatialIndexPerGraph load(Path spatialIndexFile) throws Spat
171196
LOGGER.info("Loading Spatial Index - Started: {}", spatialIndexFile);
172197

173198
try (Input input = new Input(Files.newInputStream(spatialIndexFile))) {
199+
JsonObject header = readHeader(input);
200+
201+
String type = header.get("type").getAsString();
202+
if (!"jena-spatial-index".equals(type)) {
203+
throw new RuntimeException("Type does not indicate a spatial index file.");
204+
}
205+
206+
String version = header.get("version").getAsString();
207+
if (!"2.0.0".equals(version)) {
208+
throw new SpatialIndexException("The version of the spatial index does not match the version of this loader class.");
209+
}
210+
211+
// Get the geometrySerializer attribute
212+
String geometrySerdeName = header.get("geometrySerde").getAsString();
213+
Objects.requireNonNull(geometrySerdeName, "Field 'geometrySerde' not set.");
214+
215+
GeometrySerdeAdapter geometrySerde;
216+
try {
217+
Class<?> geometrySerdeClass = Class.forName(geometrySerdeName);
218+
geometrySerde = (GeometrySerdeAdapter)geometrySerdeClass.getConstructor().newInstance();
219+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
220+
| InvocationTargetException | NoSuchMethodException | ClassCastException | SecurityException e) {
221+
throw new SpatialIndexException("Failed to load index", e);
222+
}
223+
224+
Kryo kryo = new Kryo();
225+
JtsKryoRegistrator.registerClasses(kryo, geometrySerde);
174226
srsUri = kryo.readObject(input, String.class);
175227
STRtree defaultGraphTree = kryo.readObject(input, STRtree.class);
176228
Map<Node, STRtree> graphToTree = (Map<Node, STRtree>) kryo.readClassAndObject(input);

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/serde/CustomGeometrySerde.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ public class CustomGeometrySerde
5454

5555
private GeometrySerdeAdapter geometrySerdeAdapter;
5656

57-
public CustomGeometrySerde() {
58-
this(new GeometrySerdeAdapterJtsWkb(geometryFactory));
59-
}
57+
// public CustomGeometrySerde() {
58+
// this(new GeometrySerdeAdapterJtsWkb(geometryFactory));
59+
// }
6060

6161
public CustomGeometrySerde(GeometrySerdeAdapter geometrySerdeAdapter) {
6262
super();

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/serde/CustomSpatialIndexSerde.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import com.esotericsoftware.kryo.io.Output;
2828

2929
public class CustomSpatialIndexSerde extends SpatialIndexSerde {
30+
protected GeometrySerde geometrySerde;
31+
3032
public CustomSpatialIndexSerde(GeometrySerde geometrySerde) {
3133
super(geometrySerde);
34+
this.geometrySerde = geometrySerde;
3235
}
3336

3437
@Override
@@ -40,7 +43,8 @@ public void write(Kryo kryo, Output output, Object o) {
4043
org.locationtech.jts.index.strtree.IndexSerde indexSerde
4144
= new org.locationtech.jts.index.strtree.IndexSerde();
4245
try {
43-
FieldUtils.writeField(indexSerde, "geometrySerde", new CustomGeometrySerde(), true);
46+
// FieldUtils.writeField(indexSerde, "geometrySerde", new CustomGeometrySerde(), true);
47+
FieldUtils.writeField(indexSerde, "geometrySerde", geometrySerde, true);
4448
} catch (IllegalAccessException e) {
4549
throw new RuntimeException(e);
4650
}
@@ -57,7 +61,8 @@ public Object read(Kryo kryo, Input input, Class aClass) {
5761
org.locationtech.jts.index.strtree.IndexSerde indexSerde =
5862
new org.locationtech.jts.index.strtree.IndexSerde();
5963
try {
60-
FieldUtils.writeField(indexSerde, "geometrySerde", new CustomGeometrySerde(), true);
64+
// FieldUtils.writeField(indexSerde, "geometrySerde", new CustomGeometrySerde(), true);
65+
FieldUtils.writeField(indexSerde, "geometrySerde", geometrySerde, true);
6166
} catch (IllegalAccessException e) {
6267
throw new RuntimeException(e);
6368
}

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/serde/GeometrySerdeAdapterJtsWkb.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package org.apache.jena.geosparql.spatial.serde;
1919

20+
import java.io.Serializable;
21+
2022
import org.locationtech.jts.geom.Geometry;
2123
import org.locationtech.jts.geom.GeometryFactory;
2224
import org.locationtech.jts.io.WKBReader;
@@ -28,12 +30,16 @@
2830

2931
/** Geometry de-/serialization via the WKB facilities of JTS. */
3032
public class GeometrySerdeAdapterJtsWkb
31-
implements GeometrySerdeAdapter
33+
implements GeometrySerdeAdapter, Serializable
3234
{
33-
private WKBReader geometryReader;
34-
private WKBWriter geometryWriter;
35+
private transient WKBReader geometryReader;
36+
private transient WKBWriter geometryWriter;
37+
38+
public GeometrySerdeAdapterJtsWkb() {
39+
this(new GeometryFactory());
40+
}
3541

36-
public GeometrySerdeAdapterJtsWkb(GeometryFactory geometryFactory) {
42+
private GeometrySerdeAdapterJtsWkb(GeometryFactory geometryFactory) {
3743
super();
3844
this.geometryReader = new WKBReader(geometryFactory);
3945
this.geometryWriter = new WKBWriter();

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/serde/GeometrySerdeAdapterShapeSerde.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public class GeometrySerdeAdapterShapeSerde
3434
{
3535
protected GeometryFactory geometryFactory;
3636

37+
public GeometrySerdeAdapterShapeSerde() {
38+
this(new GeometryFactory());
39+
}
40+
3741
public GeometrySerdeAdapterShapeSerde(GeometryFactory geometryFactory) {
3842
super();
3943
this.geometryFactory = geometryFactory;

jena-geosparql/src/main/java/org/apache/jena/geosparql/spatial/serde/JtsKryoRegistrator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ public class JtsKryoRegistrator {
4949

5050
final static Logger log = LoggerFactory.getLogger(JtsKryoRegistrator.class);
5151

52-
public static void registerClasses(Kryo kryo) {
53-
GeometrySerde serializer = new CustomGeometrySerde();
52+
public static void registerClasses(Kryo kryo, GeometrySerdeAdapter geometrySerde) {
53+
GeometrySerde serializer = new CustomGeometrySerde(geometrySerde);
5454
SpatialIndexSerde indexSerializer = new CustomSpatialIndexSerde(serializer);
5555

5656
log.debug("Registering custom serializers for geometry types");

0 commit comments

Comments
 (0)