Skip to content

Commit f391525

Browse files
lesserwhirlshaileyajohnson
authored andcommitted
Fix bug in partial CF Sub-convention name matches
Make sure CF Sub-conventions work even if the full conventions name attribute is not a match. Add the partial match case to the existing test.
1 parent e69c6e2 commit f391525

File tree

3 files changed

+58
-21
lines changed

3 files changed

+58
-21
lines changed

cdm/core/src/main/java/ucar/nc2/internal/dataset/CoordSystemFactory.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,12 @@ public static Optional<CoordSystemBuilder> factory(NetcdfDataset.Builder ds, Can
230230
}
231231

232232
// if the match is on the main CF convention, we need to look at possible sub-conventions or incubating conventions
233-
if (coordSysFactory != null && ds.orgFile != null && coordSysFactory.getClass().isInstance(CF1Convention.class)) {
233+
if (coordSysFactory != null && ds.orgFile != null && coordSysFactory instanceof CF1Convention.Factory) {
234234
List<String> convs = breakupConventionNames(convName);
235235
if (convs.size() > 1) {
236236
CoordSystemBuilderFactory potentialCoordSysFactory = findCfSubConvention(ds.orgFile);
237237
// only use the potentialCoordSysFactory if it is a CF sub-convention
238-
if (potentialCoordSysFactory != null
239-
&& potentialCoordSysFactory.getClass().isInstance(CFSubConventionProvider.class)) {
238+
if (potentialCoordSysFactory != null && potentialCoordSysFactory instanceof CFSubConventionProvider) {
240239
coordSysFactory = potentialCoordSysFactory;
241240
}
242241
}
@@ -294,14 +293,14 @@ private static CoordSystemBuilderFactory findCfSubConvention(NetcdfFile orgFile)
294293
// Look for Convention using isMine()
295294
for (Convention conv : conventionList) {
296295
CoordSystemBuilderFactory candidate = conv.factory;
297-
if (candidate.getClass().isInstance(CFSubConventionProvider.class) && candidate.isMine(orgFile)) {
296+
if (candidate instanceof CFSubConventionProvider && candidate.isMine(orgFile)) {
298297
return candidate;
299298
}
300299
}
301300

302301
// Use service loader mechanism isMine()
303302
for (CoordSystemBuilderFactory csb : ServiceLoader.load(CoordSystemBuilderFactory.class)) {
304-
if (csb.getClass().isInstance(CFSubConventionProvider.class) && csb.isMine(orgFile)) {
303+
if (csb instanceof CFSubConventionProvider && csb.isMine(orgFile)) {
305304
return csb;
306305
}
307306
}

cdm/core/src/test/java/ucar/nc2/dataset/TestCfSubConventionProvider.java

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@
1919
import static com.google.common.truth.Truth.assertThat;
2020

2121
import java.io.IOException;
22+
import java.util.Arrays;
23+
import java.util.List;
2224
import java.util.Optional;
2325

2426
public class TestCfSubConventionProvider {
2527

2628
private static final NetcdfDataset.Builder<?> CF_NCDB = NetcdfDataset.builder();
27-
private static final NetcdfDataset.Builder<?> YOLO_NCDB = NetcdfDataset.builder();
29+
private static final NetcdfDataset.Builder<?> YOLO_EXACT_NCDB = NetcdfDataset.builder();
30+
private static final NetcdfDataset.Builder<?> YOLO_PARTIAL_NCDB = NetcdfDataset.builder();
2831

2932
@BeforeClass
3033
public static void makeNcdBuilders() throws IOException {
3134
NetcdfFile.Builder<?> cfNcfb = NetcdfFile.builder();
32-
NetcdfFile.Builder<?> yoloNcfb = NetcdfFile.builder();
35+
NetcdfFile.Builder<?> yoloExactNcfb = NetcdfFile.builder();
36+
NetcdfFile.Builder<?> yoloPartialNcfb = NetcdfFile.builder();
3337

3438
Group.Builder cfRoot = Group.builder().setName("");
3539
cfNcfb.setRootGroup(cfRoot);
@@ -42,14 +46,30 @@ public static void makeNcdBuilders() throws IOException {
4246
throw new IOException("Error building NetcdfFile object to mock a CF netCDF file for testing.", ioe);
4347
}
4448

45-
Group.Builder yoloRoot = Group.builder().setName("");
46-
yoloNcfb.setRootGroup(yoloRoot);
47-
Attribute yoloConvAttr =
49+
Group.Builder yoloExactRoot = Group.builder().setName("");
50+
yoloExactNcfb.setRootGroup(yoloExactRoot);
51+
// exactly match the convention name
52+
Attribute yoloExactConvAttr =
4853
Attribute.builder(CDM.CONVENTIONS).setStringValue(CfSubConvForTest.CONVENTION_NAME).build();
49-
yoloRoot.addAttribute(yoloConvAttr);
50-
try (NetcdfFile yoloNcf = yoloNcfb.build()) {
51-
YOLO_NCDB.copyFrom(yoloNcf);
52-
YOLO_NCDB.setOrgFile(yoloNcf);
54+
yoloExactRoot.addAttribute(yoloExactConvAttr);
55+
try (NetcdfFile yoloExactNcf = yoloExactNcfb.build()) {
56+
YOLO_EXACT_NCDB.copyFrom(yoloExactNcf);
57+
YOLO_EXACT_NCDB.setOrgFile(yoloExactNcf);
58+
} catch (IOException ioe) {
59+
throw new IOException("Error building NetcdfFile object to mock a CF/YOLO netCDF file for testing.", ioe);
60+
}
61+
62+
Group.Builder yoloPartialRoot = Group.builder().setName("");
63+
yoloPartialNcfb.setRootGroup(yoloPartialRoot);
64+
// change up the convention name used so that it is not an exact match with the test convention name
65+
Attribute yoloPartialConvAttr = Attribute.builder(CDM.CONVENTIONS)
66+
.setStringValue(
67+
CfSubConvForTest.CONVENTION_NAME.replaceFirst(CfSubConvForTest.CONVENTAION_NAME_STARTS_WITH, "CF-1.200"))
68+
.build();
69+
yoloPartialRoot.addAttribute(yoloPartialConvAttr);
70+
try (NetcdfFile yoloPartialNcf = yoloPartialNcfb.build()) {
71+
YOLO_PARTIAL_NCDB.copyFrom(yoloPartialNcf);
72+
YOLO_PARTIAL_NCDB.setOrgFile(yoloPartialNcf);
5373
} catch (IOException ioe) {
5474
throw new IOException("Error building NetcdfFile object to mock a CF/YOLO netCDF file for testing.", ioe);
5575
}
@@ -62,10 +82,15 @@ public void testCfSubLoadOrder() throws IOException {
6282
CoordSystemBuilder cfFac = cfFacOpt.get();
6383
assertThat(cfFac).isInstanceOf(CF1Convention.class);
6484

65-
Optional<CoordSystemBuilder> yoloFacOpt = CoordSystemFactory.factory(YOLO_NCDB, null);
66-
assertThat(yoloFacOpt.isPresent());
67-
CoordSystemBuilder yoloFac = yoloFacOpt.get();
68-
assertThat(yoloFac).isInstanceOf(CfSubConvForTest.class);
69-
assertThat(yoloFac.getConventionUsed()).isEqualTo(CfSubConvForTest.CONVENTION_NAME);
85+
// both datasets (exact and partial matches of the sub-convention name) should result in the
86+
// sub-convention being used.
87+
List<NetcdfDataset.Builder<?>> subConvBuilders = Arrays.asList(YOLO_EXACT_NCDB, YOLO_PARTIAL_NCDB);
88+
for (NetcdfDataset.Builder<?> subConvBuilder : subConvBuilders) {
89+
Optional<CoordSystemBuilder> yoloFacOpt = CoordSystemFactory.factory(subConvBuilder, null);
90+
assertThat(yoloFacOpt.isPresent());
91+
CoordSystemBuilder yoloFac = yoloFacOpt.get();
92+
assertThat(yoloFac).isInstanceOf(CfSubConvForTest.class);
93+
assertThat(yoloFac.getConventionUsed()).isEqualTo(CfSubConvForTest.CONVENTION_NAME);
94+
}
7095
}
7196
}

cdm/core/src/test/java/ucar/nc2/dataset/conv/CfSubConvForTest.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,20 @@
1212
import ucar.nc2.internal.dataset.CoordSystemBuilder;
1313
import ucar.nc2.internal.dataset.spi.CFSubConventionProvider;
1414

15+
import java.util.List;
16+
17+
import static ucar.nc2.internal.dataset.CoordSystemFactory.breakupConventionNames;
18+
1519
/**
1620
* An implementation of CoordSystemBuilder for testing CFSubConvention hooks.
1721
*
1822
* @see ucar.nc2.dataset.TestCfSubConventionProvider
1923
*/
2024
public class CfSubConvForTest extends CoordSystemBuilder {
21-
public static String CONVENTION_NAME = "CF-1.200/YOLO";
25+
private static String SUBCONVENTAION_NAME = "YOLO";
26+
// public for testing
27+
public static String CONVENTAION_NAME_STARTS_WITH = "CF-1.X";
28+
public static String CONVENTION_NAME = CONVENTAION_NAME_STARTS_WITH + "/" + SUBCONVENTAION_NAME;
2229

2330
private CfSubConvForTest(NetcdfDataset.Builder<?> datasetBuilder) {
2431
super(datasetBuilder);
@@ -33,7 +40,13 @@ public boolean isMine(NetcdfFile ncfile) {
3340
if (conventionAttr != null) {
3441
String conventionValue = conventionAttr.getStringValue();
3542
if (conventionValue != null) {
36-
mine = conventionValue.equals(CONVENTION_NAME);
43+
List<String> names = breakupConventionNames(conventionValue);
44+
for (String name : names) {
45+
if (name.equalsIgnoreCase(SUBCONVENTAION_NAME)) {
46+
mine = true;
47+
break;
48+
}
49+
}
3750
}
3851
}
3952
return mine;

0 commit comments

Comments
 (0)