Skip to content

Commit 8c7ec96

Browse files
committed
Merge pull request #17 from stoutbeard/profile
Flesh out WMTS code. This does not work yet. WIP
2 parents 965a1d8 + 2c6e2b1 commit 8c7ec96

11 files changed

Lines changed: 528 additions & 4 deletions

File tree

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,15 @@
141141
<artifactId>validation-api</artifactId>
142142
<version>1.1.0.Final</version>
143143
</dependency>
144+
<dependency>
145+
<groupId>org.apache.velocity</groupId>
146+
<artifactId>velocity</artifactId>
147+
<version>1.7</version>
148+
</dependency>
144149
<dependency>
145150
<groupId>org.xerial</groupId>
146151
<artifactId>sqlite-jdbc</artifactId>
147152
<version>3.8.6</version>
148153
</dependency>
149154
</dependencies>
150-
</project>
155+
</project>

src/main/java/com/sintef/featureserver/FeatureServer.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.sintef.featureserver.netcdf.NetCdfManager;
44
import com.sintef.featureserver.providers.NetCdfManagerProvider;
5+
import com.sintef.featureserver.providers.VelocityEngineProvider;
6+
import org.apache.velocity.app.Velocity;
7+
import org.apache.velocity.app.VelocityEngine;
58
import org.cloudname.flags.Flag;
69
import org.cloudname.flags.Flags;
710

@@ -32,10 +35,22 @@ public static void main(final String[] args) throws Exception {
3235
public void start() {
3336
// Initialize providers
3437
NetCdfManagerProvider.value = new NetCdfManager();
38+
VelocityEngineProvider.velocityEngine = createVelocityEngine();
3539
final WebServer webServer = new WebServer(webserverPort);
3640
webServer.start();
3741
}
3842

43+
private static VelocityEngine createVelocityEngine() {
44+
final VelocityEngine velocityEngine = new VelocityEngine();
45+
velocityEngine.setProperty(Velocity.RUNTIME_LOG_REFERENCE_LOG_INVALID, Boolean.TRUE);
46+
velocityEngine.setProperty(Velocity.RESOURCE_MANAGER_LOGWHENFOUND, Boolean.FALSE);
47+
velocityEngine.setProperty(Velocity.RESOURCE_LOADER, "class");
48+
velocityEngine.setProperty("class.resource.loader.class",
49+
"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
50+
velocityEngine.init();
51+
return velocityEngine;
52+
}
53+
3954

4055

4156
}

src/main/java/com/sintef/featureserver/netcdf/NetCdfManager.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import java.util.ArrayList;
88
import java.util.Comparator;
99
import java.util.List;
10-
import java.util.logging.Logger;
1110
import org.joda.time.DateTime;
1211
import ucar.ma2.Array;
1312
import ucar.ma2.Index;
1413
import ucar.ma2.InvalidRangeException;
14+
import ucar.nc2.Attribute;
1515
import ucar.nc2.dataset.CoordinateAxis1D;
1616
import ucar.nc2.dataset.CoordinateAxis1DTime;
1717
import ucar.nc2.dt.GridCoordSystem;
@@ -26,7 +26,6 @@
2626
* @author Arve Nygård
2727
*/
2828
public class NetCdfManager {
29-
private static final Logger LOGGER = Logger.getLogger(NetCdfManager.class.getName());
3029

3130
/**
3231
* Gets the values of a scalar variables at the given area.
@@ -278,7 +277,7 @@ private List<NetCdfDescriptor> getCorrectFilePath(final AreaBounds bounds){
278277
}
279278

280279
/**
281-
* Get the file that contains the given point. If multiple files match, use the newest one.
280+
* Get files that contains the given point.
282281
* @param point location we are interested in
283282
* @return NetCdfDescriptor describing the file that contains this point.
284283
*/
@@ -292,4 +291,26 @@ private List<NetCdfDescriptor> getCorrectFilePath(final LatLonPoint point){
292291
);
293292
return result;
294293
}
294+
295+
public LatLonRect getBoundingBox() throws IOException {
296+
// @Todo (Arve) This needs to be maintained by the indexer once we are working with
297+
// multiple files.
298+
final GridDataset gds = ucar.nc2.dt.grid.GridDataset.open(FeatureServer.netCdfFile);
299+
300+
final List<Attribute> attrs = gds.getGlobalAttributes();
301+
302+
return gds.getBoundingBox();
303+
304+
}
305+
306+
public double getResolution() throws IOException {
307+
final GridDataset gds = ucar.nc2.dt.grid.GridDataset.open(FeatureServer.netCdfFile);
308+
final List<Attribute> globalAttributes = gds.getGlobalAttributes();
309+
for (final Attribute attr: globalAttributes) {
310+
if (attr.getName().equals("horizontal_resolution")) {
311+
return attr.getNumericValue(0).intValue(); // Single value variable.
312+
}
313+
}
314+
throw new InternalServerException("Could not parse resolution of dataset.");
315+
}
295316
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.sintef.featureserver.providers;
2+
3+
import com.sun.jersey.core.spi.component.ComponentContext;
4+
import com.sun.jersey.core.spi.component.ComponentScope;
5+
import com.sun.jersey.spi.inject.Injectable;
6+
import com.sun.jersey.spi.inject.InjectableProvider;
7+
import java.lang.reflect.Type;
8+
import javax.ws.rs.core.Context;
9+
import javax.ws.rs.ext.Provider;
10+
import org.apache.velocity.app.VelocityEngine;
11+
12+
13+
/**
14+
* A class that has a static reference to VelocityEngine.
15+
*
16+
* Used by state-less API classes in the resource package.
17+
*
18+
* @author arve
19+
*/
20+
@Provider
21+
public class VelocityEngineProvider implements InjectableProvider<Context, Type> {
22+
public static VelocityEngine velocityEngine = null;
23+
24+
@Override
25+
public ComponentScope getScope() { return ComponentScope.Singleton; }
26+
27+
@Override
28+
public Injectable getInjectable(final ComponentContext componentContext, final Context context, final Type type) {
29+
if (type.equals(VelocityEngine.class)) {
30+
return new Injectable<VelocityEngine>() {
31+
@Override
32+
public VelocityEngine getValue() {
33+
return velocityEngine;
34+
}
35+
};
36+
}
37+
38+
// Asked to provide something other than VelocityEngine. We don't do that.
39+
return null;
40+
}
41+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.sintef.featureserver.rs.wmts;
2+
3+
import com.sintef.featureserver.netcdf.NetCdfManager;
4+
import com.sintef.featureserver.util.VelocityUtil;
5+
import com.sintef.featureserver.wmts.GoogleMapsCompatibleTileMatrixSet;
6+
import com.sintef.featureserver.wmts.TileMatrix;
7+
import java.io.IOException;
8+
import java.net.URI;
9+
import javax.ws.rs.GET;
10+
import javax.ws.rs.Path;
11+
import javax.ws.rs.Produces;
12+
import javax.ws.rs.core.Context;
13+
import javax.ws.rs.core.Response;
14+
import javax.ws.rs.core.UriBuilder;
15+
import javax.ws.rs.core.UriInfo;
16+
import org.apache.velocity.Template;
17+
import org.apache.velocity.VelocityContext;
18+
import org.apache.velocity.app.VelocityEngine;
19+
import ucar.unidata.geoloc.LatLonPoint;
20+
import ucar.unidata.geoloc.LatLonRect;
21+
22+
/**
23+
* Serves the Capabilities document as prescribed by the WMTS spec.
24+
* The spec only defines an XML encoding for this document.
25+
* The path to this document is also defined by the spec.
26+
* @author arve
27+
*/
28+
29+
@Path("WMTS/1.0.0/WMTSCapabilities.xml")
30+
public class CapabilityResource {
31+
private final NetCdfManager netCdfManager;
32+
private final VelocityEngine velocityEngine;
33+
private final UriInfo uriInfo;
34+
35+
public CapabilityResource(
36+
@Context final NetCdfManager netCdfManager,
37+
@Context final UriInfo uriInfo,
38+
@Context final VelocityEngine velocityEngine) {
39+
this.netCdfManager = netCdfManager;
40+
this.velocityEngine = velocityEngine;
41+
this.uriInfo = uriInfo;
42+
43+
}
44+
45+
@GET
46+
@Produces("text/xml")
47+
public Response getCapabilities() throws IOException {
48+
49+
50+
final Template xmlTemplate
51+
= VelocityUtil.loadTemplate(velocityEngine, "capabilities.xml");
52+
final VelocityContext context = new VelocityContext();
53+
54+
final URI wmtsBaseUrl = UriBuilder.
55+
fromUri(uriInfo.getBaseUri())
56+
.path("WMTS")
57+
.build();
58+
final LatLonRect boundingBox = netCdfManager.getBoundingBox();
59+
final LatLonPoint upperLeft = boundingBox.getUpperLeftPoint();
60+
final LatLonPoint lowerRight = boundingBox.getLowerRightPoint();
61+
final GoogleMapsCompatibleTileMatrixSet tileMatrixSet
62+
= new GoogleMapsCompatibleTileMatrixSet(
63+
netCdfManager.getResolution(),
64+
netCdfManager.getBoundingBox());
65+
66+
context.put("WmtsBaseUrl", wmtsBaseUrl);
67+
context.put("upperLeftPoint", upperLeft);
68+
context.put("lowerRightPoint", lowerRight);
69+
context.put("tileMatrixSet", tileMatrixSet);
70+
final String xmlString = VelocityUtil.renderTemplate(xmlTemplate, context);
71+
return Response.ok(xmlString).build();
72+
}
73+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.sintef.featureserver.rs.wmts;
2+
3+
import com.sintef.featureserver.netcdf.NetCdfManager;
4+
import com.sintef.featureserver.wmts.GoogleMapsCompatibleTileMatrixSet;
5+
import com.sintef.featureserver.wmts.TileMatrix;
6+
import java.io.IOException;
7+
import javax.ws.rs.Path;
8+
import javax.ws.rs.PathParam;
9+
import javax.ws.rs.Produces;
10+
import javax.ws.rs.core.Context;
11+
import javax.ws.rs.core.Response;
12+
import ucar.unidata.geoloc.LatLonRect;
13+
14+
/**
15+
* Serves tiles through the WMTS protocol
16+
*
17+
* @author arve
18+
*/
19+
20+
@Path("$wmtsBaseUrl/tile/1.0.0/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png")
21+
@Produces("image/png")
22+
public class TileResource {
23+
private final NetCdfManager netCdfManager;
24+
25+
public TileResource(@Context final NetCdfManager netCdfManager) throws IOException {
26+
this.netCdfManager = netCdfManager;
27+
final GoogleMapsCompatibleTileMatrixSet tileMatrixSet
28+
= new GoogleMapsCompatibleTileMatrixSet(
29+
netCdfManager.getResolution(),
30+
netCdfManager.getBoundingBox());
31+
32+
}
33+
34+
public Response getTile(
35+
@PathParam("TileMatrixSet") final String variable,
36+
@PathParam("TileMatrix") final int zoomLevel,
37+
@PathParam("TileRow") final int tileRow,
38+
@PathParam("TileMatrix") final int TileCol) throws IOException {
39+
40+
final double resolution = netCdfManager.getResolution();
41+
final LatLonRect bbox = netCdfManager.getBoundingBox();
42+
final GoogleMapsCompatibleTileMatrixSet tileMatrixSet
43+
= new GoogleMapsCompatibleTileMatrixSet(resolution, bbox);
44+
final TileMatrix tileMatrix = tileMatrixSet.getTileMatrices().get(zoomLevel);
45+
46+
47+
return Response.ok().build();
48+
}
49+
50+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.sintef.featureserver.util;
2+
3+
import java.io.StringWriter;
4+
import org.apache.velocity.Template;
5+
import org.apache.velocity.VelocityContext;
6+
import org.apache.velocity.app.VelocityEngine;
7+
8+
/**
9+
* Utility functions relating to Velocity Template engine.
10+
*/
11+
public final class VelocityUtil {
12+
13+
private static final String UTF_8 = "UTF-8";
14+
15+
private VelocityUtil() {} // Should not be instantiated.
16+
17+
public static Template loadTemplate(
18+
final VelocityEngine velocityEngine,
19+
final String templateName) {
20+
return velocityEngine.getTemplate(templateName, UTF_8);
21+
}
22+
23+
public static String renderTemplate(final Template template, final VelocityContext context) {
24+
final StringWriter writer = new StringWriter();
25+
template.merge(context, writer);
26+
return writer.toString();
27+
}
28+
29+
}

0 commit comments

Comments
 (0)