20
20
import java .io .IOException ;
21
21
import java .io .OutputStream ;
22
22
import java .lang .invoke .MethodHandles ;
23
+ import java .lang .reflect .InvocationTargetException ;
23
24
import java .nio .file .Files ;
24
25
import java .nio .file .Path ;
25
26
import java .util .Map ;
27
+ import java .util .Objects ;
26
28
27
29
import org .apache .jena .atlas .RuntimeIOException ;
28
30
import org .apache .jena .atlas .io .IOX ;
31
33
import org .apache .jena .geosparql .implementation .registry .SRSRegistry ;
32
34
import org .apache .jena .geosparql .implementation .vocabulary .SRS_URI ;
33
35
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 ;
34
38
import org .apache .jena .geosparql .spatial .serde .JtsKryoRegistrator ;
35
39
import org .apache .jena .graph .Node ;
36
40
import org .apache .jena .query .Dataset ;
41
45
import com .esotericsoftware .kryo .Kryo ;
42
46
import com .esotericsoftware .kryo .io .Input ;
43
47
import com .esotericsoftware .kryo .io .Output ;
48
+ import com .google .gson .Gson ;
49
+ import com .google .gson .JsonObject ;
44
50
45
51
public class SpatialIndexIoKryo {
46
52
private static final Logger LOGGER = LoggerFactory .getLogger (MethodHandles .lookup ().lookupClass ());
@@ -137,20 +143,42 @@ public static final void save(Path spatialIndexFile, SpatialIndexPerGraph index)
137
143
* @param index spatial index
138
144
*/
139
145
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
+
140
153
Kryo kryo = new Kryo ();
141
- JtsKryoRegistrator .registerClasses (kryo );
154
+ JtsKryoRegistrator .registerClasses (kryo , geometrySerde );
142
155
try (Output output = new Output (os )) {
156
+ writeJson (output , header );
143
157
writeIndex (kryo , output , index );
144
158
output .flush ();
145
159
}
146
160
}
147
161
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
+
148
168
public static void writeIndex (Kryo kryo , Output output , SpatialIndexPerGraph index ) {
149
169
kryo .writeObject (output , index .getSrsInfo ().getSrsURI ());
150
170
kryo .writeObject (output , index .getIndex ().getDefaultTree ());
151
171
kryo .writeClassAndObject (output , index .getIndex ().getNamedTreeMap ());
152
172
}
153
173
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
+
154
182
/**
155
183
* Load a SpatialIndex from file.<br>
156
184
* 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
160
188
* @throws SpatialIndexException
161
189
*/
162
190
public static final SpatialIndexPerGraph load (Path spatialIndexFile ) throws SpatialIndexException {
163
- Kryo kryo = new Kryo ();
164
- JtsKryoRegistrator .registerClasses (kryo );
165
-
166
191
String srsUri ;
167
192
STRtreePerGraph index ;
168
193
@@ -171,6 +196,33 @@ public static final SpatialIndexPerGraph load(Path spatialIndexFile) throws Spat
171
196
LOGGER .info ("Loading Spatial Index - Started: {}" , spatialIndexFile );
172
197
173
198
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 );
174
226
srsUri = kryo .readObject (input , String .class );
175
227
STRtree defaultGraphTree = kryo .readObject (input , STRtree .class );
176
228
Map <Node , STRtree > graphToTree = (Map <Node , STRtree >) kryo .readClassAndObject (input );
0 commit comments