<< Click to Display Table of Contents >> Navigation: Development > Client > Java Library > Custom Implementation Usage |
This example shows a more complex implementation of a DTSClient, where we extend the class and customize elements to suit our purposes.
First, the Client (CustomClient.java):
import com.alloy.dts.DTSException;
import com.alloy.dts.client.*;
import com.alloy.dts.model.DTSPredicate;
import com.alloy.dts.record.StreamRecord;
import com.alloy.dts.type.DTSTypesClusterManager;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.alloy.dts.type.DTSTypes.*;
public class CustomClient extends DTSClient {
// Our client will be a singleton for ease of use throughout the application
private static CustomClient instance;
public static CustomClient getInstance() {
if (instance == null) {
instance = new CustomClient();
}
return instance;
}
// We will only use one collection, so let's keep it here
DTSRemoteCollection collection;
public CustomClient() {
super();
// we also want to override some root types in our client
initSpecialTypes();
}
private void initSpecialTypes() {
// overriding types is as simple as calling this static method on DTSTypesClusterManager
// but be aware that you will most likely need to define and implement
// custom Serialization/Deserialization routines
DTSTypesClusterManager.overrideRootType(GEOMETRY_TYPE, CustomGeometry.class);
DTSTypesClusterManager.overrideRootType(POINT_TYPE, CustomGeometry.class);
DTSTypesClusterManager.overrideRootType(LINE_TYPE, CustomGeometry.class);
DTSTypesClusterManager.overrideRootType(AREA_TYPE, CustomGeometry.class);
}
// We override the open() method to automatically wait for our endpoint and set our collection
@Override
public void open(String projectName) throws TimeoutException, DTSException{
super.open(projectName);
DTSDatasource ds = getDatasource(projectName);
if (!ds.waitForEndpoints(Arrays.asList("myOnlyConnector"), 60 * 1000)) {
throw new DTSException("No endpoint", ex);
}
collection = ds.getEndpoint("myOnlyConnector").getCollection("public.all_things");
}
// We decide we want our client to react in some way when a stream times out
@Override
public void onClosedStream(String streamId) {
System.out.println("Stream " + streamId + " has timed out!");
/*
do something
*/
}
// and here is the point of our implementation - a nice shortcut to getting the geometric center of an object
public double[] getObjectCenter(String objectId) throws Exception {
// we only need 1 record, but we still need a stream
// we'll use another way of managing it this time
// first we get the DTSRemoteRecordStream object using createStream on the collection (which gets fed our query predicate)
DTSRemoteRecordStream stream = collection.createStream(DTSPredicate.eq("id", objectId));
// then we advance the stream by 1 so that the record we're looking for makes its way into the buffer
stream.advance(1);
// then we grab the record from the buffer
StreamRecord object = (StreamRecord) stream.getCurrentRecordContainer().getRecords().get(0);
// we use the getFieldValue() method to extract the geometry (which will be in our CustomGeometry format because we overrode the types)
CustomGeometry geom = (CustomGeometry) object.getFieldValue("geom");
// and finally call a method we created on CustomGeometry that calculates its center
// while this particular result could easily be obtained without overriding root types and defining custom deserializers
// we are using it to illustrate a point and it is easy to see how this can be a powerful tool in more complex scenarios
return geom.getCenter();
}
}
The CustomGeometry class we're using (CustomGeometry.java):
import com.alloy.dts.DTSException;
import com.alloy.dts.type.json.geojson.GeoJson;
import com.alloy.dts.type.json.geojson.GeoJsonLineString;
import com.alloy.dts.type.json.geojson.GeoJsonPoint;
import com.alloy.dts.type.json.geojson.GeoJsonPolygon;
import java.util.ArrayList;
public class CustomGeometry {
// We'll hold the GeoJson that comes through
private GeoJson originalGeom;
public GeoJson getOriginalGeom() {
return originalGeom;
}
public void setOriginalGeom(GeoJson originalGeom) {
this.originalGeom = originalGeom;
}
// And calculate the center when needed
public double[] getCenter() throws DTSException {
if (getOriginalGeom() instanceof GeoJsonPoint) {
// trivial...
GeoJsonPoint point = (GeoJsonPoint) getOriginalGeom();
return point.getCoordinates();
} else if (getOriginalGeom() instanceof GeoJsonLineString) {
// naive...
GeoJsonLineString line = (GeoJsonLineString) getOriginalGeom();
ArrayList<double[]> coords = line.getCoordinates();
return new double[] {
(coords.get(0)[0] - coords.get(coords.size()-1)[0]) / 2,
(coords.get(0)[1] - coords.get(coords.size()-1)[1]) / 2
};
} else if (getOriginalGeom() instanceof GeoJsonPolygon) {
// eh...
throw new DTSException("Not worth it...");
}
throw new DTSException("Unsupported geometry");
}
}
And the custom Deserializer (CustomGeometryDeserializer.java):
// the package is important here! In order for the deserializer to register, it needs to be in this package!
package com.alloy.dts.type.json;
import com.mypackage.CustomGeometry;
import com.alloy.dts.type.json.geojson.GeoJson;
import com.google.gson.*;
import java.lang.reflect.Type;
// Our deserializer needs to implement JsonDeserializer<the_class_we_want_to_output>
public class CustomGeometryDeserializer implements JsonDeserializer<CustomGeometry> {
public static void registerWithGsonBuilder(GsonBuilder builder){
builder.registerTypeAdapter(CustomGeometry.class, new CustomGeometryDeserializer());
}
// And here is where we implement our deserialization
@Override
public CustomGeometry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// We simply use the deserialization context to deserialize the object to the class it was meant to be
GeoJson geoJson = context.deserialize(json, GeoJson.class);
// The we create our custom object and place the original geometry inside it
CustomGeometry geom = new CustomGeometry();
geom.setOriginalGeom(geoJson);
return geom;
}
}