Skip to content

Commit 9cdc14a

Browse files
author
haileyajohnson
authored
Merge branch 'maint-5.x' into fix_gradle_dependency_keywords_in_docs
2 parents dce3210 + ba624f5 commit 9cdc14a

8 files changed

Lines changed: 290 additions & 2 deletions

File tree

docs/src/site/_data/sidebars/netcdfJavaTutorial_sidebar.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,10 @@ entries:
267267
url: /read_over_http.html
268268
output: web, pdf
269269

270+
- title: Reading Zarr
271+
url: /reading_zarr.html
272+
output: web, pdf
273+
270274
- title: Standard Horizontal Coordinate Transforms
271275
url: /std_horizonal_coord_transforms.html
272276
output: web, pdf
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
title: Reading the Zarr data model
3+
last_updated: 2021-12-22
4+
sidebar: netcdfJavaTutorial_sidebar
5+
toc: false
6+
permalink: reading_zarr.html
7+
---
8+
## Zarr
9+
10+
As of version 5.5.1, the netCDF-Java library provides read-only support for the [Zarr v2 data model](https://zarr.readthedocs.io/en/stable/spec/v2.html#){:target="_blank"}.
11+
Any dataset that adheres to the v2 spec can be read into a `NetcdfFile` object, as long as the following is true:
12+
13+
* all filters and compressors used by the dataset must be known to the netCDF-Java library (see [Filters](reading_zarr.html#filters))
14+
* the underlying storage of the dataset must be a directory store, zip store, or object store
15+
16+
### Enabling Zarr support
17+
18+
To use Zarr in the netCDF-Java library, you must include the `cdm-zarr` module in your netCDF-Java build.
19+
See [here](using_netcdf_java_artifacts.html) for more information on including optional modules.
20+
21+
### How to read a Zarr dataset
22+
23+
Reading a Zarr dataset is syntactically the same as reading a netCDF file:
24+
25+
{% capture rmd %}
26+
{% includecodeblock netcdf-java&docs/src/test/java/examples/ZarrExamples.java&readZarrStores %}
27+
{% endcapture %}
28+
{{ rmd | markdownify }}
29+
30+
If the file is a legal Zarr dataset, the library will map it to a `NetcdfFile` object for reading.
31+
See [reading CDM files](reading_cdm.html) for more examples on accessing data once the `NetcdfFile` object is returned.
32+
33+
## Filters
34+
35+
As of netCDF-Java version 5.5.1, a `ucar.nc2.filter` package is included, that provides a suite of implemented filters and compressors,
36+
as well as a mechanism for user-supplied filters. This package is used by both the Zarr and HDF5 IOSPs, and is available for public use.
37+
38+
The current list of filters included natively in the netCDF-Java library is:
39+
40+
* Deflate (zlib)
41+
* Shuffle
42+
* 32-bit Checksum (CRC, Fletcher, and Adler)
43+
* ScaleOffset
44+
45+
This list is still expanding, but if the filter you are looking for is not provided at this time, you are able to provide it yourself
46+
(See [Implementing a Filter](#implementing-a-filter)) for details.)
47+
48+
### Implementing a Filter
49+
50+
To add a user-supplied `Filter` to the netDF-Java library, you will have to provide two classes:
51+
52+
* A class that extends the `ucar.nc2.filter.Filter` abstract class
53+
* A class that implements the `ucar.nc2.filter.FilterProvider` interface
54+
55+
Once implemented, you will need to include these classes as JAR files in your classpath. See [here](runtime_loading.html) for more information.
56+
57+
#### `Filter` implementation
58+
59+
To implement a user-supplied filter, you will need to extend the abstract `ucar.nc2.filter.Filter` class, and provide implementations for the following methods:
60+
* `encode` takes a `byte[]` of unfiltered data and returns a `byte[]` of filtered data
61+
* `decode` takes a `byte[]` of filtered data and returns a `byte[]` of unfiltered data
62+
63+
Your `Filter` class should look something like this:
64+
65+
{% capture rmd %}
66+
{% includecodeblock netcdf-java&docs/src/test/java/examples/ZarrExamples.java&implementFilter %}
67+
{% endcapture %}
68+
{{ rmd | markdownify }}
69+
70+
#### `FilterProvider` implementation
71+
72+
For the netCDF-Java library to find your `Filter` implementation, you will need to provide a `FilterProvider` as well.
73+
74+
{% capture rmd %}
75+
{% includecodeblock netcdf-java&docs/src/test/java/examples/ZarrExamples.java&implementFilterProvider %}
76+
{% endcapture %}
77+
{{ rmd | markdownify }}
78+
79+
{%include note.html content="
80+
`getName` and `getId`
81+
When reading data, [IOSPs](writing_iosp.html) can look up filters by either a `String` or `int` (name or id). Currently, the `ucar.nc2.filter`
82+
package is shared by the Zarr and HDF5 IOSPs. The Zarr IOSP looks up filters by name; if you plan to use your third party filter with Zarr data,
83+
the string returned by `getName` should match that specified by the [NumCodecs](https://numcodecs.readthedocs.io/en/stable/) library.
84+
The HDF5 IOSP looks up filters by id; if you plan to use your third party filter with HDF5 data, the int returned by `getId` should adhere to the
85+
[guidelines](https://portal.hdfgroup.org/display/support/Registered+Filter+Plugins) set by the HDF group.
86+
If your filter is registered with the HDF group, your `getId` method should return the HDF id. If your filter is not registered with the HDF group,
87+
" %}
88+
89+
There are two more methods in the `FilterProvider` interface: the `canProvide` methods. By default, these methods work as follows:
90+
* `boolean canProvide(String name)` returns true if the string returned by `getName()` matches the string passed to the method
91+
* `boolean canProvide(int id)` returns true if the int returned by `getId()` matches the int passed to the method
92+
93+
It is unlikely that you would want to override these methods, as the netCDF-Java [IOSPs](writing_iosp.html) look for the correct filter implementations
94+
for a dataset by either name or numeric id. However, it is possible to write your own implementation of `canProvide`; for example, the
95+
following `FilterProvider` returns an instance of a `DefaultFilter` regardless of the name or id provided.
96+
97+
{% capture rmd %}
98+
{% includecodeblock netcdf-java&docs/src/test/java/examples/ZarrExamples.java&implementFilterProvider2 %}
99+
{% endcapture %}
100+
{{ rmd | markdownify }}

docs/src/site/pages/netcdfJava/Upgrade.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Point release notes:
3737

3838
5.5.x is the first release that includes read support for [Zarr](https://zarr.readthedocs.io/en/stable/index.html){:target="_blank"}.
3939
There is also a new package for filters, `ucar.ma2.filters`, which allows user-provided compressors and filters to be supplied through a [Service Provider Interface](https://www.baeldung.com/java-spi){:target="_blank"}.
40+
Read about Zarr support and the `filter` package [here](reading_zarr.html)
4041

4142
## netCDF-Java API Changes (5.4.x)
4243

docs/src/site/pages/netcdfJava/developer/FileTypes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ To register your format/IOServiceProvider, or to send corrections and additions
5050
| UAMIV | CAMx UAM-IV formatted files | `cdm-radial` | <http://www.camx.com/> |
5151
| UniversalRadarFormat | Universal Radar Format | `cdm-radial` | <ftp://ftp.sigmet.com/outgoing/manuals/program/cuf.pdf> |
5252
| USPLN | US Precision Lightning Network | `cdm-misc` | <http://www.uspln.com/> |
53-
| VIS5D | Vis5D grid file | `cdm-vs5d` | <http://www.ssec.wisc.edu/~billh/vis5d.html>
53+
| VIS5D | Vis5D grid file | `cdm-vs5d` | <http://www.ssec.wisc.edu/~billh/vis5d.html>|
54+
| Zarr | Zarr dataset | `cdm-zarr` | <https://zarr.readthedocs.io/en/stable/> |

docs/src/site/pages/netcdfJava_tutorial/runtime/runtimeloading.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ See [GribTables](grib_tables.html) for more information about lookup tables.
8888

8989
The file must be a [BUFR table lookup file](bufr_tables.html).
9090

91+
### Register a `Filter` implementation:
92+
Users-supplied filters must be provided using the [Service Provider](https://docs.oracle.com/javase/tutorial/ext/basics/spi.html){:target="_blank"}
93+
mechanism and included in a JAR on the classpath, where it is dynamically loaded at runtime.
94+
In your JAR, include a file named `META-INF/services/ucar.nc2.filter.FilterProvider` containing the name(s) of your implementations, eg:
95+
96+
~~~
97+
ucar.nc2.filter.BloscFilter
98+
ucar.nc2.filter.GZipFilter
99+
~~~
100+
101+
Your `FilterProvider` classes must implement the `ucar.nc2.filter.FilterProvider` interface.
102+
See [here](reading_zarr.html#implementing-a-filter) for details on implementing user-supplied filters.
103+
91104
## Runtime Configuration
92105

93106
Instead of calling the above routines in your code, you can pass the CDM library an XML configuration file.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package examples;
2+
3+
import ucar.ma2.Array;
4+
import ucar.ma2.InvalidRangeException;
5+
import ucar.ma2.Section;
6+
import ucar.nc2.Group;
7+
import ucar.nc2.NetcdfFile;
8+
import ucar.nc2.NetcdfFiles;
9+
import ucar.nc2.Variable;
10+
import ucar.nc2.filter.Filter;
11+
import ucar.nc2.filter.FilterProvider;
12+
import ucar.nc2.filter.Filters;
13+
import ucar.nc2.filter.Shuffle;
14+
import ucar.nc2.iosp.AbstractIOServiceProvider;
15+
import ucar.nc2.util.CancelTask;
16+
import ucar.unidata.io.RandomAccessFile;
17+
import ucar.unidata.util.test.TestDir;
18+
19+
import java.io.IOException;
20+
import java.util.Map;
21+
22+
public class ZarrExamples {
23+
24+
private static String pathToDirectoryStore = "";
25+
private static String pathToZipStore = "";
26+
private static String pathToObjectStore = "";
27+
28+
public static void readZarrStores() throws IOException {
29+
// a local file path
30+
NetcdfFile directoryStoreZarr = NetcdfFiles.open(pathToDirectoryStore);
31+
// a local file path + '.zip'
32+
NetcdfFile zipdirectoryStoreZarr = NetcdfFiles.open(pathToZipStore);
33+
// an object store path, sarting with 'cdms3:' and ending with 'delimiter=' + the store delimiter
34+
NetcdfFile objectStoreZarr = NetcdfFiles.open(pathToObjectStore);
35+
}
36+
37+
public static void implementFilter() {
38+
byte[] dataOut = null;
39+
/* DOCS-IGNORE */
40+
/* INSERT public */class MyFilter extends Filter {
41+
42+
@Override
43+
public byte[] encode(byte[] dataIn) throws IOException {
44+
// your encoding implementation here
45+
return dataOut;
46+
}
47+
48+
@Override
49+
public byte[] decode(byte[] dataIn) throws IOException {
50+
// your decoding implementation here
51+
return dataOut;
52+
}
53+
}
54+
}
55+
56+
public static void implementFilterProvider() {
57+
/* INSERT public */class MyFilterProvider implements FilterProvider {
58+
59+
@Override
60+
public String getName() {
61+
// returns a string identifier for your filter
62+
return "myFilter"; // see notes on filter names and ids
63+
}
64+
65+
@Override
66+
public int getId() {
67+
// returns a numeric identifier for your filter
68+
return 32768; // see notes on filter names and ids
69+
}
70+
71+
@Override
72+
public Filter create(Map<String, Object> properties) {
73+
return new MyFilter(properties); // return an instance of your filter
74+
}
75+
}
76+
}
77+
78+
public static void implementFilterProvider2() {
79+
/* INSERT public */class DefaultFilterProvider implements FilterProvider {
80+
81+
@Override
82+
public String getName() {
83+
return "defaultFilter";
84+
}
85+
86+
@Override
87+
public int getId() {
88+
return -1;
89+
}
90+
91+
@Override
92+
public boolean canProvide(String name) {
93+
return true;
94+
}
95+
96+
@Override
97+
public boolean canProvide(int id) {
98+
return true;
99+
}
100+
101+
@Override
102+
public Filter create(Map<String, Object> properties) {
103+
return new DefaultFilter(properties); // return an instance of your filter
104+
}
105+
}
106+
}
107+
108+
/**
109+
* Shell classes for code snippets
110+
*/
111+
static class MyFilter extends Filter {
112+
113+
public MyFilter(Map<String, Object> properties) {
114+
super();
115+
}
116+
117+
@Override
118+
public byte[] encode(byte[] dataIn) throws IOException {
119+
return new byte[0];
120+
}
121+
122+
@Override
123+
public byte[] decode(byte[] dataIn) throws IOException {
124+
return new byte[0];
125+
}
126+
}
127+
128+
static class DefaultFilter extends Filter {
129+
130+
public DefaultFilter(Map<String, Object> properties) {
131+
super();
132+
}
133+
134+
@Override
135+
public byte[] encode(byte[] dataIn) throws IOException {
136+
return new byte[0];
137+
}
138+
139+
@Override
140+
public byte[] decode(byte[] dataIn) throws IOException {
141+
return new byte[0];
142+
}
143+
}
144+
}

docs/src/test/java/examples/writingiosp/LightningExampleTutorial.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public String getFileTypeDescription() {
5959
return "Data from lightning data test file";
6060
}
6161
}
62-
return new UspLightning();
62+
return new UspLightning(); /* DOCS-IGNORE */
6363
}
6464

6565
/**
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package tests;
2+
3+
import examples.ZarrExamples;
4+
import org.junit.Assert;
5+
import org.junit.Test;
6+
7+
import java.io.FileNotFoundException;
8+
9+
public class TestZarrExamples {
10+
11+
@Test
12+
public void testReadZarrExample() {
13+
Assert.assertThrows(FileNotFoundException.class, () -> {
14+
ZarrExamples.readZarrStores();
15+
});
16+
}
17+
18+
@Test
19+
public void testImplementFilterAndProvider() {
20+
// just verify the example code compiles with no deprecations
21+
ZarrExamples.implementFilter();
22+
ZarrExamples.implementFilterProvider();
23+
ZarrExamples.implementFilterProvider2();
24+
}
25+
}

0 commit comments

Comments
 (0)