diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilderTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilderTest.java index bde8c955..6bf09f11 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilderTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilderTest.java @@ -23,7 +23,7 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusFileBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; @@ -35,7 +35,7 @@ public class TomoApplicationBuilderTest { - public static class TestPositioner extends AbstractNexusProvider { + public static class TestPositioner extends AbstractNexusObjectProvider { public TestPositioner() { super("positioner", NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); @@ -86,7 +86,8 @@ public void testSetTitle_dataNode() { @Test public void testSetSource() throws Exception { tomoBuilder.addDefaultGroups(); - NexusObjectProvider sourceProvider = new AbstractNexusProvider(NexusBaseClass.NX_SOURCE) { + NexusObjectProvider sourceProvider = new AbstractNexusObjectProvider( + "source", NexusBaseClass.NX_SOURCE) { @Override protected NXsource doCreateNexusObject(NexusNodeFactory nodeFactory) { @@ -108,7 +109,8 @@ protected NXsource doCreateNexusObject(NexusNodeFactory nodeFactory) { @Test public void testSetDetector() throws Exception { tomoBuilder.addDefaultGroups(); - NexusObjectProvider detectorProvider = new AbstractNexusProvider(NexusBaseClass.NX_DETECTOR) { + NexusObjectProvider detectorProvider = + new AbstractNexusObjectProvider("detector", NexusBaseClass.NX_DETECTOR) { @Override protected NXdetector doCreateNexusObject( @@ -135,7 +137,8 @@ protected NXdetector doCreateNexusObject( @Test public void testSetSample() throws NexusException { tomoBuilder.addDefaultGroups(); - NexusObjectProvider sampleProvider = new AbstractNexusProvider(NexusBaseClass.NX_SAMPLE) { + NexusObjectProvider sampleProvider = new AbstractNexusObjectProvider( + "sample", NexusBaseClass.NX_SAMPLE) { @Override protected NXsample doCreateNexusObject(NexusNodeFactory nodeFactory) { diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilderTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilderTest.java similarity index 70% rename from org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilderTest.java rename to org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilderTest.java index beb48b2e..e3c77be0 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilderTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilderTest.java @@ -1,4 +1,4 @@ -package org.eclipse.dawnsci.nexus.builder.impl; +package org.eclipse.dawnsci.nexus.builder.data.impl; import static org.eclipse.dawnsci.nexus.test.util.NexusAssert.assertAxes; import static org.eclipse.dawnsci.nexus.test.util.NexusAssert.assertIndices; @@ -16,20 +16,23 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; -import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; -import org.eclipse.dawnsci.nexus.builder.NexusFileBuilder; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.AxisDataDevice; +import org.eclipse.dawnsci.nexus.builder.data.DataDeviceBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.PrimaryDataDevice; +import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusEntryBuilder; +import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusFileBuilder; import org.junit.Before; import org.junit.Test; public class DefaultNexusDataBuilderTest { - public static class TestDetector extends AbstractNexusProvider { + public static class TestDetector extends AbstractNexusObjectProvider { public TestDetector() { - super("testDetector", NexusBaseClass.NX_DETECTOR); + super("testDetector", NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA); } @Override @@ -41,12 +44,12 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class MultipleFieldTestDetector extends AbstractNexusProvider { + public static class TestDetectorWithAxisField extends AbstractNexusObjectProvider { - public MultipleFieldTestDetector() { + public TestDetectorWithAxisField() { super("detector2", NexusBaseClass.NX_DETECTOR); - setPrimaryDataField(NXdetector.NX_DATA); - addDataField(NXdetector.NX_TIME_OF_FLIGHT, 2); + setPrimaryDataFieldName(NXdetector.NX_DATA); + addAxisDataField(NXdetector.NX_TIME_OF_FLIGHT, 2, null); } @Override @@ -61,12 +64,12 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class MultipleDataFieldTestDetector extends AbstractNexusProvider { + public static class TestDetectorWithMultiplePrimaryDataFields extends AbstractNexusObjectProvider { - public MultipleDataFieldTestDetector() { + public TestDetectorWithMultiplePrimaryDataFields() { super("detector", NexusBaseClass.NX_DETECTOR); - setPrimaryDataField(NXdetector.NX_DATA); - addDataField("sum", null); + setPrimaryDataFieldName(NXdetector.NX_DATA); + addAdditionalPrimaryDataFieldName("sum"); } @Override @@ -80,10 +83,10 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestDetectorWithExternalLink extends AbstractNexusProvider { + public static class TestDetectorWithExternalLink extends AbstractNexusObjectProvider { public TestDetectorWithExternalLink() { - super("testDetector", NexusBaseClass.NX_DETECTOR); + super("testDetector", NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA); setExternalFileName("external.nxs"); } @@ -97,7 +100,7 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestPositioner extends AbstractNexusProvider { + public static class TestPositioner extends AbstractNexusObjectProvider { public TestPositioner() { super("positioner", NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); @@ -117,11 +120,12 @@ protected NXpositioner doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class MultipleFieldTestPositioner extends AbstractNexusProvider { + public static class MultipleFieldTestPositioner extends AbstractNexusObjectProvider { public MultipleFieldTestPositioner() { super("ss1", NexusBaseClass.NX_POSITIONER); - setDataFields("field1", "field2", "field3", "field4"); + setUseDeviceNameInNXdata(false); + setAxisDataFieldNames("field1", "field2", "field3", "field4"); } @Override @@ -136,7 +140,7 @@ protected NXpositioner doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestPositionerWithExternalLink extends AbstractNexusProvider { + public static class TestPositionerWithExternalLink extends AbstractNexusObjectProvider { public TestPositionerWithExternalLink() { super("positioner", NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); @@ -159,12 +163,21 @@ protected NXpositioner doCreateNexusObject(NexusNodeFactory nodeFactory) { @Before public void setUp() throws Exception { - NexusFileBuilder fileBuilder = new DefaultNexusFileBuilder("test"); - NexusEntryBuilder entryBuilder = fileBuilder.newEntry(); + DefaultNexusFileBuilder fileBuilder = new DefaultNexusFileBuilder("test"); + DefaultNexusEntryBuilder entryBuilder = fileBuilder.newEntry(); + entryBuilder.addDefaultGroups(); dataBuilder = entryBuilder.createDefaultData(); nxData = dataBuilder.getNxData(); } + private void addToEntry(NexusObjectProvider... nexusObjects) throws NexusException { + // TODO it would be good to be able to add fields from a group that hasn't been created already + NexusNodeFactory nodeFactory = new NexusNodeFactory(); + for (NexusObjectProvider nexusObjectProvider : nexusObjects) { + nexusObjectProvider.createNexusObject(nodeFactory); + } + } + @Test public void testGetNxData() { assertThat(dataBuilder.getNxData(), notNullValue()); @@ -177,6 +190,7 @@ public void testSetPrimaryDataDevice() throws NexusException { assertThat(nxData.getNumberOfDataNodes(), is(0)); TestDetector detector = new TestDetector(); + addToEntry(detector); dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); @@ -196,7 +210,9 @@ public void testSetPrimaryDataDevice_useDeviceName() throws NexusException { assertThat(nxData.getNumberOfDataNodes(), is(0)); TestDetector detector = new TestDetector(); - dataBuilder.setPrimaryDevice(new DataDevice<>(detector, true)); + detector.setUseDeviceNameInNXdata(true); + addToEntry(detector); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -214,14 +230,15 @@ public void testSetPrimaryDataDevice_setSignalFieldName() throws NexusException assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(0)); - MultipleFieldTestDetector detector = new MultipleFieldTestDetector(); - DataDevice dataDevice = new DataDevice<>(detector, false); - dataDevice.setPrimaryDataSourceFieldName(NXdetector.NX_TIME_OF_FLIGHT); + TestDetectorWithAxisField detector = new TestDetectorWithAxisField(); + addToEntry(detector); + PrimaryDataDevice dataDevice = DataDeviceBuilder.newPrimaryDataDevice(detector, + NXdetector.NX_TIME_OF_FLIGHT); dataBuilder.setPrimaryDevice(dataDevice); - assertThat(nxData.getNumberOfAttributes(), is(4)); + assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); - assertThat(nxData.getNumberOfDataNodes(), is(2)); + assertThat(nxData.getNumberOfDataNodes(), is(1)); assertSignal(nxData, NXdetector.NX_TIME_OF_FLIGHT); assertAxes(nxData, "."); @@ -235,11 +252,12 @@ public void testSetPrimaryDataDevice_multipleFields() throws NexusException { assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(0)); - MultipleFieldTestDetector detector = new MultipleFieldTestDetector(); - DataDevice dataDevice = new DataDevice<>(detector); - dataDevice.setUseDeviceName(false); - dataDevice.setDestinationFieldName(NXdetector.NX_TIME_OF_FLIGHT, "tof"); - dataBuilder.setPrimaryDevice(dataDevice); + TestDetectorWithAxisField detector = new TestDetectorWithAxisField(); + addToEntry(detector); + DataDeviceBuilder detectorDataDevice = + DataDeviceBuilder.newPrimaryDataDeviceBuilder(detector); + detectorDataDevice.setDestinationFieldName(NXdetector.NX_TIME_OF_FLIGHT, "tof"); + dataBuilder.setPrimaryDevice((PrimaryDataDevice) detectorDataDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -255,15 +273,16 @@ public void testSetPrimaryDataDevice_multipleFields() throws NexusException { } @Test - public void testSetPrimaryDataDevice_fieldName() throws NexusException { + public void testSetPrimaryDataDevice_setDestinationFieldName() throws NexusException { assertThat(nxData.getNumberOfAttributes(), is(1)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(0)); TestDetector detector = new TestDetector(); - DataDevice detectorDataDevice = new DataDevice<>(detector); + addToEntry(detector); + DataDeviceBuilder detectorDataDevice = new DataDeviceBuilder<>(detector, true); detectorDataDevice.setDestinationFieldName(NXdetector.NX_DATA, "foo"); - dataBuilder.setPrimaryDevice(detectorDataDevice); + dataBuilder.setPrimaryDevice((PrimaryDataDevice) detectorDataDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -282,6 +301,7 @@ public void testSetPrimaryDataDevice_externalLink() throws Exception { assertThat(nxData.getNumberOfDataNodes(), is(0)); TestDetectorWithExternalLink detector = new TestDetectorWithExternalLink(); + addToEntry(detector); dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); @@ -295,15 +315,17 @@ public void testSetPrimaryDataDevice_externalLink() throws Exception { } @Test - public void testAddDataDevice() throws NexusException { + public void testAddAxisDevice() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - dataBuilder.addDataDevice(positioner, null, 0); + dataBuilder.addAxisDevice(positioner, null, 0); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -316,15 +338,17 @@ public void testAddDataDevice() throws NexusException { } @Test - public void testAddDataDevice_defaultAxisForDimension() throws NexusException { + public void testAddAxisDevice_defaultAxisForDimension() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - dataBuilder.addDataDevice(positioner, 0); + dataBuilder.addAxisDevice(positioner, 0); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -337,18 +361,23 @@ public void testAddDataDevice_defaultAxisForDimension() throws NexusException { } @Test - public void testAddDataDevice_sourceFieldName() throws NexusException { + public void testAddAxisDevice_setSourceFieldName() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + positioner.setUseDeviceNameInNXdata(false); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - DataDevice axisDevice = new DataDevice<>(positioner, null, 0); - axisDevice.setUseDeviceName(false); - axisDevice.setSourceFields("source"); - dataBuilder.addDataDevice(axisDevice); + DataDeviceBuilder axisDevice = DataDeviceBuilder.newAxisDataDeviceBuilder( + positioner); + axisDevice.clearAxisFields(); + axisDevice.addAxisField("source"); + axisDevice.setDefaultAxisSourceFieldName("source"); + dataBuilder.addAxisDevice((AxisDataDevice) axisDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -361,22 +390,26 @@ public void testAddDataDevice_sourceFieldName() throws NexusException { } @Test - public void testAddDataDevice_sourceFieldName_defaultAxisForDimension() throws NexusException { + public void testAddAxisDevice_sourceFieldName_defaultAxisForDimension() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + positioner.setUseDeviceNameInNXdata(false); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - DataDevice dataDevice = new DataDevice<>(positioner, 0); - dataDevice.setUseDeviceName(false); - dataDevice.addSourceField("source", 0); - dataBuilder.addDataDevice(dataDevice); + DataDeviceBuilder axisDevice = DataDeviceBuilder.newAxisDataDeviceBuilder( + positioner); + axisDevice.clearAxisFields(); + axisDevice.addAxisField("source", 0); + dataBuilder.addAxisDevice((AxisDataDevice) axisDevice.build()); - assertThat(nxData.getNumberOfAttributes(), is(5)); + assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); - assertThat(nxData.getNumberOfDataNodes(), is(3)); + assertThat(nxData.getNumberOfDataNodes(), is(2)); assertAxes(nxData, "source", ".", "."); assertIndices(nxData, "source", 0); @@ -385,18 +418,21 @@ public void testAddDataDevice_sourceFieldName_defaultAxisForDimension() throws N } @Test - public void testAddDataDevice_sourceAndDestinationFieldNames() throws NexusException { + public void testAddAxisDevice_sourceAndDestinationFieldNames() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - DataDevice dataDevice = new DataDevice<>(positioner, null, 0); - dataDevice.setUseDeviceName(false); - dataDevice.clearSourceFields().addSourceField("source", "dest"); - dataBuilder.addDataDevice(dataDevice); + DataDeviceBuilder axisDevice = DataDeviceBuilder.newAxisDataDeviceBuilder( + positioner); + axisDevice.setAxisFields("source"); + axisDevice.setDestinationFieldName("source", "dest"); + dataBuilder.addAxisDevice((AxisDataDevice) axisDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -409,18 +445,22 @@ public void testAddDataDevice_sourceAndDestinationFieldNames() throws NexusExcep } @Test - public void testAddDataDevice_sourceAndDestinationFieldNames_defaultAxisForDimension() throws NexusException { + public void testAddAxisDevice_sourceAndDestinationFieldNames_defaultAxisForDimension() throws NexusException { TestDetector detector = new TestDetector(); + TestPositioner positioner = new TestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositioner positioner = new TestPositioner(); - DataDevice dataDevice = new DataDevice<>(positioner, false, 1); - dataDevice.setUseDeviceName(false); - dataDevice.setDestinationFieldName(NXpositioner.NX_VALUE, "dest"); - dataBuilder.addDataDevice(dataDevice); + DataDeviceBuilder axisDevice = DataDeviceBuilder.newAxisDataDeviceBuilder( + positioner, 1); + axisDevice.setAxisFields("source"); + axisDevice.setDefaultAxisSourceFieldName("source"); + axisDevice.setDestinationFieldName("source", "dest"); + dataBuilder.addAxisDevice((AxisDataDevice) axisDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); @@ -429,55 +469,56 @@ public void testAddDataDevice_sourceAndDestinationFieldNames_defaultAxisForDimen assertAxes(nxData, ".", "dest", "."); assertIndices(nxData, "dest", 1); assertThat(nxData.getDataNode("dest"), is(sameInstance( - positioner.getNexusObject().getDataNode(NXpositioner.NX_VALUE)))); + positioner.getNexusObject().getDataNode("source")))); } @Test - public void testAddDataDevice_multipleFields() throws NexusException { + public void testAddAxisDevice_multipleFields() throws NexusException { TestDetector detector = new TestDetector(); + MultipleFieldTestPositioner positioner = new MultipleFieldTestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - MultipleFieldTestPositioner positioner = new MultipleFieldTestPositioner(); -// DataDevice axisDevice = new DataDevice<>(positioner, new int[] { 0 }); -// axisDevice.setUseDeviceName(false); - dataBuilder.addDataDevice(positioner, 0); -// dataBuilder.addDevice(axisDevice); + dataBuilder.addAxisDevice(positioner, 0); assertThat(nxData.getNumberOfAttributes(), is(7)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(5)); - assertAxes(nxData, ".", ".", "."); - for (String sourceFieldName : positioner.getDataFields()) { - String destinationFieldName = positioner.getName() + "_" + sourceFieldName; - assertIndices(nxData, destinationFieldName, 0); - assertThat(nxData.getDataNode(destinationFieldName), is(sameInstance( + assertAxes(nxData, "field1", ".", "."); + for (String sourceFieldName : positioner.getAxisDataFieldNames()) { + assertIndices(nxData, sourceFieldName, 0); + assertThat(nxData.getDataNode(sourceFieldName), is(sameInstance( positioner.getNexusObject().getDataNode(sourceFieldName)))); } } @Test - public void testAddDataDevice_multipleFields_defaultAxisForDimension() throws NexusException { + public void testAddAxisDevice_multipleFields_defaultAxisForDimension() throws NexusException { TestDetector detector = new TestDetector(); + MultipleFieldTestPositioner positioner = new MultipleFieldTestPositioner(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - MultipleFieldTestPositioner positioner = new MultipleFieldTestPositioner(); - DataDevice axisDevice = new DataDevice<>(positioner, false, "field3", 2); - axisDevice.setUseDeviceName(false); - dataBuilder.addDataDevice(axisDevice); + DataDeviceBuilder axisDevice = DataDeviceBuilder.newAxisDataDeviceBuilder( + positioner, "field3", 2); + dataBuilder.addAxisDevice((AxisDataDevice) axisDevice.build()); assertThat(nxData.getNumberOfAttributes(), is(7)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(5)); assertAxes(nxData, ".", ".", "field3"); - for (String sourceFieldName : positioner.getDataFields()) { + for (String sourceFieldName : positioner.getAxisDataFieldNames()) { + assertIndices(nxData, sourceFieldName, sourceFieldName.equals("field3") ? 2 : 0); assertThat(nxData.getDataNode(sourceFieldName), is(sameInstance( positioner.getNexusObject().getDataNode(sourceFieldName)))); @@ -485,15 +526,17 @@ public void testAddDataDevice_multipleFields_defaultAxisForDimension() throws Ne } @Test - public void testAddDataDevice_externalLink() throws Exception { + public void testAddAxisDevice_externalLink() throws Exception { TestDetector detector = new TestDetector(); + TestPositionerWithExternalLink positioner = new TestPositionerWithExternalLink(); + addToEntry(detector, positioner); + dataBuilder.setPrimaryDevice(detector); assertThat(nxData.getNumberOfAttributes(), is(3)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); assertThat(nxData.getNumberOfDataNodes(), is(1)); - TestPositionerWithExternalLink positioner = new TestPositionerWithExternalLink(); - dataBuilder.addDataDevice(positioner, 0); + dataBuilder.addAxisDevice(positioner, 0); assertThat(nxData.getNumberOfAttributes(), is(4)); assertThat(nxData.getNumberOfGroupNodes(), is(0)); diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataExamplesTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataExamplesTest.java similarity index 82% rename from org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataExamplesTest.java rename to org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataExamplesTest.java index d3257838..0daa3e01 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataExamplesTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataExamplesTest.java @@ -1,4 +1,4 @@ -package org.eclipse.dawnsci.nexus.builder.impl; +package org.eclipse.dawnsci.nexus.builder.data.impl; import static org.eclipse.dawnsci.nexus.test.util.NexusAssert.assertAxes; import static org.eclipse.dawnsci.nexus.test.util.NexusAssert.assertIndices; @@ -16,23 +16,24 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusFileBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.DataDeviceBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusFileBuilder; import org.junit.Before; import org.junit.Test; /** - * This test class tests that the {@link DefaultNexusDataBuilder} + * This test class tests that DefaultNexusDataBuilder * can construct the example {@link NXdata} structures from the * document http://wiki.nexusformat.org/2014_axes_and_uncertainties. */ public class DefaultNexusDataExamplesTest { - public static class TestDetector extends AbstractNexusProvider { + public static class TestDetector extends AbstractNexusObjectProvider { private final int[] shape; @@ -43,10 +44,16 @@ public TestDetector(int... shape) { } public TestDetector(String name, int... shape) { + this(name, true, shape); + } + + public TestDetector(String name, boolean useDeviceName, int... shape) { super(name, NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA); + setUseDeviceNameInNXdata(useDeviceName); this.shape = shape; } + @Override protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { NXdetector detector = nodeFactory.createNXdetector(); @@ -60,7 +67,7 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestPositioner extends AbstractNexusProvider { + public static class TestPositioner extends AbstractNexusObjectProvider { private final int[] shape; @@ -78,7 +85,7 @@ protected NXpositioner doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class PolarAnglePositioner extends AbstractNexusProvider { + public static class PolarAnglePositioner extends AbstractNexusObjectProvider { private final int dimensionIndex; @@ -88,8 +95,8 @@ public PolarAnglePositioner(String name, int dimensionIndex, int[] scanShape) { super(name, NexusBaseClass.NX_POSITIONER); this.dimensionIndex = dimensionIndex; this.scanShape = scanShape; - setDataFields("rbv", "demand"); - setDemandDataField("demand"); + setAxisDataFieldNames("rbv", "demand"); + setDefaultAxisDataFieldName("demand"); } @Override @@ -131,7 +138,7 @@ public void testExample1() throws NexusException { addToEntry(detector, positioner); dataBuilder.setPrimaryDevice(detector); - dataBuilder.addDataDevice(positioner, 0); + dataBuilder.addAxisDevice(positioner, 0); assertSignal(nxData, "data"); assertAxes(nxData, "x"); @@ -153,9 +160,9 @@ public void testExample2() throws NexusException { addToEntry(mainDetector, pressureDet, temperatureDet, timeDet); dataBuilder.setPrimaryDevice(mainDetector); - dataBuilder.addDataDevice(pressureDet, 1); - dataBuilder.addDataDevice(temperatureDet, null, 1); - dataBuilder.addDataDevice(timeDet, 0); + dataBuilder.addAxisDevice(pressureDet, 1); + dataBuilder.addAxisDevice(temperatureDet, null, 1); + dataBuilder.addAxisDevice(timeDet, 0); assertSignal(nxData, "data"); assertAxes(nxData, "time", "pressure"); @@ -181,14 +188,14 @@ public void testExample2() throws NexusException { */ @Test public void testExample3() throws NexusException { - TestDetector mainDetector = new TestDetector("det", 100, 100000); + TestDetector mainDetector = new TestDetector("det", true, 100, 100000); TestDetector pressureDetector = new TestDetector("pressure", 100); TestDetector tofDetector = new TestDetector("tof", 100000); addToEntry(mainDetector, pressureDetector, tofDetector); - dataBuilder.setPrimaryDevice(new DataDevice<>(mainDetector, true)); - dataBuilder.addDataDevice(pressureDetector, 0); - dataBuilder.addDataDevice(tofDetector, 1); + dataBuilder.setPrimaryDevice(mainDetector); + dataBuilder.addAxisDevice(pressureDetector, 0); + dataBuilder.addAxisDevice(tofDetector, 1); assertSignal(nxData, "det"); assertAxes(nxData, "pressure", "tof"); @@ -213,10 +220,10 @@ public void testExample4() throws NexusException { TestPositioner yPositioner = new TestPositioner("y", 100, 512); addToEntry(mainDetector, tofDetector, xPositioner, yPositioner); - dataBuilder.setPrimaryDevice(new DataDevice<>(mainDetector)); - dataBuilder.addDataDevice(tofDetector, 2); - dataBuilder.addDataDevice(xPositioner, 0, 0, 1); - dataBuilder.addDataDevice(yPositioner, 1, 0, 1); + dataBuilder.setPrimaryDevice(DataDeviceBuilder.newPrimaryDataDevice(mainDetector)); + dataBuilder.addAxisDevice(tofDetector, 2); + dataBuilder.addAxisDevice(xPositioner, 0, 0, 1); + dataBuilder.addAxisDevice(yPositioner, 1, 0, 1); assertSignal(nxData, "det"); assertAxes(nxData, "x", "y", "tof"); @@ -241,10 +248,10 @@ public void testExample5() throws NexusException { TestPositioner timePositioner = new TestPositioner("time", 50, 5); addToEntry(mainDetector, polarAnglePositioner, frameNumberPositioner, timePositioner); - dataBuilder.setPrimaryDevice(new DataDevice<>(mainDetector)); - dataBuilder.addDataDevice(polarAnglePositioner, 0, 0, 1); - dataBuilder.addDataDevice(frameNumberPositioner, 1); - dataBuilder.addDataDevice(timePositioner, null, 0, 1); + dataBuilder.setPrimaryDevice(DataDeviceBuilder.newPrimaryDataDevice(mainDetector)); + dataBuilder.addAxisDevice(polarAnglePositioner, 0, 0, 1); + dataBuilder.addAxisDevice(frameNumberPositioner, 1); + dataBuilder.addAxisDevice(timePositioner, null, 0, 1); assertSignal(nxData, "det1"); assertAxes(nxData, "polar_angle_demand", "frame_number", "."); diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/ComplexNexusFileBuilderTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/ComplexNexusFileBuilderTest.java index 9916d7f2..8908de29 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/ComplexNexusFileBuilderTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/ComplexNexusFileBuilderTest.java @@ -27,23 +27,20 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.CustomNexusEntryModification; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryModification; import org.eclipse.dawnsci.nexus.builder.appdef.impl.TomoApplicationBuilder; -import org.eclipse.dawnsci.nexus.builder.impl.MapBasedMetadataProvider; -import org.eclipse.dawnsci.nexus.builder.impl.NexusUser; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; public class ComplexNexusFileBuilderTest extends AbstractNexusFileBuilderTestBase { - private static class SimplePositioner extends AbstractNexusProvider { + private static class SimplePositioner extends AbstractNexusObjectProvider { public SimplePositioner(final String name) { - super(name, NexusBaseClass.NX_POSITIONER, NexusBaseClass.NX_INSTRUMENT, NXpositioner.NX_VALUE); + super(name, NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); } @Override @@ -57,11 +54,12 @@ public NXpositioner doCreateNexusObject( } - private static final class TomoScanDevicePositioner extends AbstractNexusProvider { + private static final class TomoScanDevicePositioner extends AbstractNexusObjectProvider { public TomoScanDevicePositioner() { super("tomoScanDevice", NexusBaseClass.NX_POSITIONER, "ss1_rot"); - setDataFields("imageNumber", "image_key", "ss1_X", "ss1_rot", "tomography_shutter"); + setUseDeviceNameInNXdata(false); + setAxisDataFieldNames("imageNumber", "image_key", "ss1_X", "ss1_rot", "tomography_shutter"); } @Override @@ -79,10 +77,11 @@ public NXpositioner doCreateNexusObject( } - private static class TestDetector extends AbstractNexusProvider { + private static class TestDetector extends AbstractNexusObjectProvider { public TestDetector() { - super("pc01_hw_hdf", NexusBaseClass.NX_DETECTOR); + super("pc01_hw_hdf", NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA, + NXdetector.NX_COUNT_TIME, "start_time", "time_ms"); } @Override @@ -106,7 +105,7 @@ public NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - private static class TestSource extends AbstractNexusProvider { + private static class TestSource extends AbstractNexusObjectProvider { public TestSource() { super("source", NexusBaseClass.NX_SOURCE); @@ -130,7 +129,7 @@ protected NXsource doCreateNexusObject(NexusNodeFactory nodeFactory) { * In the real world the before_scan collection is used by GDA to store additional data it needs. * In a real world system this provider could fetch the details from the scan. */ - private static class BeforeScan extends AbstractNexusProvider { + private static class BeforeScan extends AbstractNexusObjectProvider { public BeforeScan() { super("before_scan", NexusBaseClass.NX_COLLECTION); @@ -224,7 +223,6 @@ protected List getNexusTreeModifications() { scanData.addMetadataEntry("scan_identifier", "a3d668c0-e3c4-4ed9-b127-4a202b2b6bac"); scanData.addMetadataEntry("title", "AKingUVA_7050wSSwire_InSitu_95RH_2MMgCl2_p4ul_p4h"); - List nexusObjects = new ArrayList<>(); nexusObjects.add(beforeScan); nexusObjects.add(scanData); @@ -255,15 +253,19 @@ protected void configureEntryModel(NexusEntryBuilder nexusEntryModel) { protected void addDataBuilder(NexusEntryBuilder entryModel) throws NexusException { NexusDataBuilder dataBuilder = entryModel.newData(testDetector.getName()); dataBuilder.setPrimaryDevice(testDetector); - dataBuilder.addDataDevice(new DataDevice<>(tomoScanDevicePositioner, false, 0, 0)); - dataBuilder.addDataDevice(actualTimePositioner, null, 0); - dataBuilder.addDataDevice(beamOkPositioner, null, 0); - dataBuilder.addDataDevice(ioncIPositioner, null, 0); + + dataBuilder.addAxisDevice(tomoScanDevicePositioner, 0); + dataBuilder.addAxisDevice(actualTimePositioner); + dataBuilder.addAxisDevice(beamOkPositioner); + dataBuilder.addAxisDevice(ioncIPositioner); - DataDevice detectorAxisDevice = new DataDevice<>(testDetector, null, 0); - detectorAxisDevice.setSourceFields("count_time", "start_time", "time_ms"); - detectorAxisDevice.setUseDeviceName(false); - dataBuilder.addDataDevice(detectorAxisDevice); + // TODO, add these fields as part of the detector (primary) device + // TODO also add region_origin and region_size +// AxisDataDevice detectorAxisDevice = new DataDevice<>(testDetector), null, 0); +// detectorAxisDevice.setSourceFields("count_time", "start_time", "time_ms"); +// detectorAxisDevice.set +// detectorAxisDevice.setIsPrimary(true); +// dataBuilder.addDataDevice(detectorAxisDevice); } protected void addApplicationDefinitions(NexusEntryBuilder nexusEntryModel) throws NexusException { diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilderTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilderTest.java index 5290f326..7144d442 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilderTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilderTest.java @@ -24,13 +24,13 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.CustomNexusEntryModification; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryModification; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.appdef.NexusApplicationBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusFileBuilder; import org.eclipse.dawnsci.nexus.builder.impl.MapBasedMetadataProvider; import org.eclipse.dawnsci.nexus.validation.NexusValidationException; @@ -39,7 +39,7 @@ public class DefaultNexusEntryBuilderTest { - public static class TestPositioner extends AbstractNexusProvider { + public static class TestPositioner extends AbstractNexusObjectProvider { public TestPositioner() { super("positioner", NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); @@ -56,10 +56,10 @@ protected NXpositioner doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestDetector extends AbstractNexusProvider { + public static class TestDetector extends AbstractNexusObjectProvider { public TestDetector() { - super(NexusBaseClass.NX_DETECTOR); + super("detector", NexusBaseClass.NX_DETECTOR); } @Override @@ -69,10 +69,10 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - public static class TestSource extends AbstractNexusProvider { + public static class TestSource extends AbstractNexusObjectProvider { public TestSource() { - super(NexusBaseClass.NX_SOURCE); + super("source", NexusBaseClass.NX_SOURCE); } @Override @@ -171,7 +171,8 @@ public void testAdd_samplePositioner() throws NexusException { @Test public void testAdd_sample() throws NexusException { - NexusObjectProvider sampleProvider = new AbstractNexusProvider(NexusBaseClass.NX_SAMPLE) { + NexusObjectProvider sampleProvider = + new AbstractNexusObjectProvider("sample", NexusBaseClass.NX_SAMPLE) { @Override protected NXsample doCreateNexusObject(NexusNodeFactory nodeFactory) { diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/SimpleNexusFileBuilderTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/SimpleNexusFileBuilderTest.java index 02f11e05..22f9e753 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/SimpleNexusFileBuilderTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/builder/impl/SimpleNexusFileBuilderTest.java @@ -23,15 +23,15 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryModification; +import org.eclipse.dawnsci.nexus.builder.data.DataDeviceBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; public class SimpleNexusFileBuilderTest extends AbstractNexusFileBuilderTestBase { - private static class TestDetector extends AbstractNexusProvider { + private static class TestDetector extends AbstractNexusObjectProvider { public TestDetector() { super("analyser", NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA); @@ -50,10 +50,11 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { } - private static class TestBeam extends AbstractNexusProvider { + private static class TestBeam extends AbstractNexusObjectProvider { public TestBeam() { - super("beam", NexusBaseClass.NX_BEAM, NexusBaseClass.NX_SAMPLE, null); + super("beam", NexusBaseClass.NX_BEAM); + setCategory(NexusBaseClass.NX_SAMPLE); } @Override @@ -79,7 +80,7 @@ protected String getFilename() { protected void addDataBuilder(NexusEntryBuilder entryModel) throws NexusException { NexusDataBuilder dataModel = entryModel.createDefaultData(); - dataModel.setPrimaryDevice(new DataDevice<>(detector, false)); + dataModel.setPrimaryDevice(DataDeviceBuilder.newPrimaryDataDevice(detector)); } protected List getNexusTreeModifications() { diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/MultipleThreadNexusFileWriteTest.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/MultipleThreadNexusFileWriteTest.java index 47ae4741..5cea83cb 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/MultipleThreadNexusFileWriteTest.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/MultipleThreadNexusFileWriteTest.java @@ -38,11 +38,11 @@ import org.eclipse.dawnsci.nexus.NexusNodeFactory; import org.eclipse.dawnsci.nexus.ServiceHolder; import org.eclipse.dawnsci.nexus.TestUtils; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusFileBuilder; import org.eclipse.dawnsci.nexus.builder.NexusScanFile; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusFileBuilder; import org.eclipse.dawnsci.nexus.test.util.NexusTestUtils; import org.junit.Before; @@ -52,7 +52,7 @@ public class MultipleThreadNexusFileWriteTest { private static abstract class AbstractTestDevice - extends AbstractNexusProvider + extends AbstractNexusObjectProvider implements Callable { private int nextStepNumber = 0; @@ -130,7 +130,7 @@ protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { @Override protected void writeNewData(int stepNumber) throws Exception { - final ILazyWriteableDataset dataset = getDefaultWriteableDataset(); + final ILazyWriteableDataset dataset = getWriteableDataset(NXdetector.NX_DATA); final int[] startPos = new int[] { stepNumber, 0, 0 }; final int[] stopPos = new int[] { stepNumber + 1, numRows, numColumns }; @@ -181,7 +181,7 @@ public void initializeScan(final long stepTime, final int numSteps) { @Override protected void writeNewData(int stepNumber) throws Exception { - final ILazyWriteableDataset dataset = getDefaultWriteableDataset(); + final ILazyWriteableDataset dataset = getWriteableDataset(NXpositioner.NX_VALUE); final int[] startPos = new int[] { stepNumber }; final int[] stopPos = new int[] { stepNumber + 1 }; @@ -236,7 +236,7 @@ private void createNexusFile(final int numPositioners) throws NexusException { final NexusDataBuilder dataBuilder = entryBuilder.createDefaultData(); dataBuilder.setPrimaryDevice(detector); for (TestPositioner positioner : positioners) { - dataBuilder.addDataDevice(positioner); + dataBuilder.addAxisDevice(positioner); } nexusScanFile = fileBuilder.createFile(); diff --git a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/util/NexusAssert.java b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/util/NexusAssert.java index 61b8bf48..ebbf151a 100644 --- a/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/util/NexusAssert.java +++ b/org.eclipse.dawnsci.nexus.test/src/org/eclipse/dawnsci/nexus/test/util/NexusAssert.java @@ -1,9 +1,9 @@ package org.eclipse.dawnsci.nexus.test.util; -import static org.eclipse.dawnsci.nexus.builder.NexusDataBuilder.ATTR_NAME_AXES; -import static org.eclipse.dawnsci.nexus.builder.NexusDataBuilder.ATTR_NAME_SIGNAL; -import static org.eclipse.dawnsci.nexus.builder.NexusDataBuilder.ATTR_NAME_TARGET; -import static org.eclipse.dawnsci.nexus.builder.NexusDataBuilder.ATTR_SUFFIX_INDICES; +import static org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder.ATTR_NAME_AXES; +import static org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder.ATTR_NAME_SIGNAL; +import static org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder.ATTR_NAME_TARGET; +import static org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder.ATTR_SUFFIX_INDICES; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; diff --git a/org.eclipse.dawnsci.nexus/META-INF/MANIFEST.MF b/org.eclipse.dawnsci.nexus/META-INF/MANIFEST.MF index 9509b13b..ea202e58 100644 --- a/org.eclipse.dawnsci.nexus/META-INF/MANIFEST.MF +++ b/org.eclipse.dawnsci.nexus/META-INF/MANIFEST.MF @@ -15,6 +15,7 @@ Export-Package: org.eclipse.dawnsci.nexus, org.eclipse.dawnsci.nexus.builder, org.eclipse.dawnsci.nexus.builder.appdef, org.eclipse.dawnsci.nexus.builder.appdef.impl, + org.eclipse.dawnsci.nexus.builder.data, org.eclipse.dawnsci.nexus.builder.impl, org.eclipse.dawnsci.nexus.validation Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.dawnsci.nexus/autogen/org/eclipse/dawnsci/nexus/NexusBaseClass.java b/org.eclipse.dawnsci.nexus/autogen/org/eclipse/dawnsci/nexus/NexusBaseClass.java index c67f2cfe..99546420 100644 --- a/org.eclipse.dawnsci.nexus/autogen/org/eclipse/dawnsci/nexus/NexusBaseClass.java +++ b/org.eclipse.dawnsci.nexus/autogen/org/eclipse/dawnsci/nexus/NexusBaseClass.java @@ -7,7 +7,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * This file was auto-generated from the NXDL XML definition. - * Generated at: 2016-04-13T10:39:11+01:00 + * Generated at: 2016-05-17T16:19:59.899+01:00 *******************************************************************************/ package org.eclipse.dawnsci.nexus; @@ -95,8 +95,6 @@ public String toString() { /** * Returns the nexus base class constant for the given name string. - * @throws IllegalArgumentException if there is no such base class for the given name - * @return the base class with the given name */ public static NexusBaseClass getBaseClassForName(final String name) { // Note: this method will not work correctly if any base classes include @@ -104,5 +102,6 @@ public static NexusBaseClass getBaseClassForName(final String name) { final String enumName = name.substring(0, 2) + '_' + name.substring(2).toUpperCase(); return NexusBaseClass.valueOf(enumName); } + } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/INexusDevice.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/INexusDevice.java index f7795ee1..e8fbfba7 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/INexusDevice.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/INexusDevice.java @@ -1,7 +1,7 @@ package org.eclipse.dawnsci.nexus; import org.eclipse.dawnsci.analysis.dataset.impl.LazyDataset; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.CustomNexusEntryModification; import org.eclipse.dawnsci.nexus.builder.DelegateNexusProvider; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; @@ -9,7 +9,7 @@ /** * Any device which can write NeXus should implement this interface. * - * This can be done easily by extending {@link AbstractNexusProvider} or + * This can be done easily by extending {@link AbstractNexusObjectProvider} or * {@link DelegateNexusProvider} * * @author Matthew Gerring diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusProvider.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusObjectProvider.java similarity index 54% rename from org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusProvider.java rename to org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusObjectProvider.java index 08ec352e..8a79ecd9 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusProvider.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/AbstractNexusObjectProvider.java @@ -14,17 +14,20 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import org.eclipse.dawnsci.analysis.api.dataset.ILazyWriteableDataset; +import org.eclipse.dawnsci.nexus.NXdata; import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.impl.PrimaryDataFieldModel; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.impl.PrimaryDataFieldModel; /** * Abstract implementation of {@link NexusObjectProvider}. @@ -38,7 +41,7 @@ class Detector implements IRunnableDevice, INexusDevice { private NexusObjectProvider prov; public Detector() { - prov = new AbstractNexusProvider(NexusBaseClass.NX_DETECTOR) { + prov = new AbstractNexusObjectProvider(NexusBaseClass.NX_DETECTOR) { protected NXdetector doCreateNexusObject(NexusNodeFactory nodeFactory) { final NXdetectorImpl detector = nodeFactory.createNXdetector(); @@ -62,7 +65,7 @@ public void write(...) { * * @param nexus base class type, a subinterface of {@link NXobject} */ -public abstract class AbstractNexusProvider implements NexusObjectProvider { +public abstract class AbstractNexusObjectProvider implements NexusObjectProvider { public static final String DEFAULT_DATA_NODE_NAME = "data"; @@ -72,75 +75,71 @@ public abstract class AbstractNexusProvider implements Nexus private String name; - private final LinkedHashSet dataFieldNames; + private String primaryDataFieldName = null; + + private final LinkedHashSet axisDataFieldNames; private final List additionalPrimaryDataFieldNames; - private Map primaryDataFieldModels; + private Map primaryDataFieldModels = null; private String externalFileName = null; private Map externalDatasetRanks = null; - private String demandDataFieldName = null; + private String defaultAxisDataFieldName = null; - private String defaultWritableDataFieldName = null; + private NexusBaseClass category = null; - private NexusBaseClass category; - - public AbstractNexusProvider(NexusBaseClass nexusBaseClass) { - this(getDefaultName(nexusBaseClass), nexusBaseClass); - } + private Boolean useDeviceNameInNXdata = null; /** - * Creates a new {@link AbstractNexusProvider} for given name and base class type, - * with "data" as the name of the default data field - used as the default - * data field (i.e. the signal field) when this device is added to an NXdata. - * @param name name - * @param nexusBaseClass base class type - */ - public AbstractNexusProvider(String name, NexusBaseClass nexusBaseClass) { - this(name, nexusBaseClass, null, DEFAULT_DATA_NODE_NAME); - } - - /** - * Creates a new {@link AbstractNexusProvider} for given name, base class type + * Creates a new {@link AbstractNexusObjectProvider} for given name, base class type * and data node name. * @param name name * @param nexusBaseClass base class type */ - public AbstractNexusProvider(String name, NexusBaseClass nexusBaseClass, - String defaultDataFieldName) { - this(name, nexusBaseClass, null, defaultDataFieldName); + public AbstractNexusObjectProvider(String name, NexusBaseClass nexusBaseClass) { + this(name, nexusBaseClass, null); } /** - * Creates a new {@link AbstractNexusProvider} for given name, base class type, - * data node name and category. + * Creates a new {@link AbstractNexusObjectProvider} for given name, base class type + * and data node name. The default data field will be used as the @signal + * for an {@link NexusBaseClass#NX_DETECTOR} when building an {@link NXdata} for this object, + * otherwise if this device is the default axis for a particular dimension of the + * @signal field of the device, this is the field that will be added to the + * @axes attribute of the {@link NXdata} group for that dimension. + * * @param name name * @param nexusBaseClass base class type - * @param category - * @param defaultDataFieldName name of the default data field + * @param defaultDataFieldName default data field, the default signal field for a detector, + * the default axis field for any other type of nexus object + * @param additionalDataFieldNames the names of any additional data fields */ - public AbstractNexusProvider(String name, NexusBaseClass nexusBaseClass, - NexusBaseClass category, String defaultDataFieldName, String... remainingDataFieldNames) { + public AbstractNexusObjectProvider(String name, NexusBaseClass nexusBaseClass, + String defaultDataFieldName, String... additionalDataFieldNames) { this.name = name; this.nexusBaseClass = nexusBaseClass; - this.category = category; + this.axisDataFieldNames = new LinkedHashSet<>(additionalDataFieldNames.length); - this.defaultWritableDataFieldName = defaultDataFieldName; - this.dataFieldNames = new LinkedHashSet<>(remainingDataFieldNames.length + 1); - if (defaultDataFieldName != null) { - this.dataFieldNames.add(defaultDataFieldName); + if (nexusBaseClass == NexusBaseClass.NX_DETECTOR) { + setPrimaryDataFieldName(defaultDataFieldName); + } else { + setDefaultAxisDataFieldName(defaultDataFieldName); } - if (remainingDataFieldNames.length > 0) { - this.dataFieldNames.addAll(Arrays.asList(remainingDataFieldNames)); + + if (additionalDataFieldNames.length > 0) { + this.axisDataFieldNames.addAll(Arrays.asList(additionalDataFieldNames)); } + // field names should be prefixed by the device name for axis devices (e.g. positioners) + setUseDeviceNameInNXdata(nexusBaseClass != NexusBaseClass.NX_DETECTOR); + this.additionalPrimaryDataFieldNames = new ArrayList<>(); } public static String getDefaultName(NexusBaseClass nexusBaseClass) { - // the default name is the base class name without the initial 'NX', + // the default name is the base class name without the initial 'NX' prefix, // e.g. for 'NXpositioner' the default name is 'positioner' return nexusBaseClass.toString().substring(2); } @@ -227,7 +226,7 @@ public void setExternalFileName(String externalFileName) { /** * A convenience method to add an external link to the given * group node with the given name, while also setting the rank of the - * external dataset within this {@link AbstractNexusProvider}. + * external dataset within this {@link AbstractNexusObjectProvider}. * This is required to be set when adding a {@link NexusObjectProvider} * with external links to a {@link NexusDataBuilder} in order for the * axes and <axisname>_indices to be @@ -286,54 +285,114 @@ public void setExternalDatasetRank(String fieldName, int rank) { * @see org.eclipse.dawnsci.nexus.builder.NexusObjectProvider#getDefaultDataFieldName() */ @Override - public String getPrimaryDataField() { - if (defaultWritableDataFieldName != null) { - return defaultWritableDataFieldName; + public String getPrimaryDataFieldName() { + if (primaryDataFieldName != null) { + return primaryDataFieldName; } - if (dataFieldNames != null && !dataFieldNames.isEmpty()) { - return dataFieldNames.iterator().next(); + + // if the primary data field name hasn't been set, just use the first field + if (axisDataFieldNames != null && !axisDataFieldNames.isEmpty()) { + return axisDataFieldNames.iterator().next(); } return null; } - public void setPrimaryDataField(String defaultWritableDataFieldName) { - addDataFields(defaultWritableDataFieldName); // add as a data field if not already present - this.defaultWritableDataFieldName = defaultWritableDataFieldName; + /** + * Sets the name of the field to use as the primary data field. If this device is the + * primary device for a scan then this field is used as the @signal field + * for the {@link NXdata} group. + * @param primaryDataFieldName name of the primary data field + */ + public void setPrimaryDataFieldName(String primaryDataFieldName) { + this.primaryDataFieldName = primaryDataFieldName; } @Override - public String getDemandDataField() { - return demandDataFieldName; + public String getDefaultAxisDataFieldName() { + return defaultAxisDataFieldName; } - public void setDemandDataField(String demandDataFieldName) { - this.demandDataFieldName = demandDataFieldName; - if (!dataFieldNames.contains(demandDataFieldName)) { - dataFieldNames.add(demandDataFieldName); - } + /** + * Sets the name of the data field for this device that acts as an axis. + * This field should only be set if this device is a scannable, i.e. a device that is + * set to a position at a particular point in the scan. + * @param defaultAxisDataFieldName + */ + public void setDefaultAxisDataFieldName(String defaultAxisDataFieldName) { + this.defaultAxisDataFieldName = defaultAxisDataFieldName; + axisDataFieldNames.add(defaultAxisDataFieldName); } @Override - public List getDataFields() { - return new ArrayList(dataFieldNames); + public List getAxisDataFieldNames() { + return new ArrayList(axisDataFieldNames); } - public void setDataFields(String... dataFieldNames) { - this.dataFieldNames.clear(); - this.dataFieldNames.addAll(Arrays.asList(dataFieldNames)); + /** + * Sets the names of the data fields for this device. Each data field will be added + * to any {@link NXdata} group created for this scan. + * @param axisDataFieldNames names of data fields + */ + public void setAxisDataFieldNames(String... axisDataFieldNames) { + this.axisDataFieldNames.clear(); + this.axisDataFieldNames.addAll(Arrays.asList(axisDataFieldNames)); } - public void addDataFields(String... dataFieldName) { - this.dataFieldNames.addAll(Arrays.asList(dataFieldName)); + /** + * Adds the given name to the names of the axis data fields for this device. Each data field + * will be added to any {@link NXdata} group created for this scan (an {@link NXdata} group is + * created for each primary data field). In order to add a data field that should only + * be added to the {@link NXdata} group for a specific primary data field use + * {@link #addAxisDataFieldForPrimaryDataField(String, String, Integer, int...)} + * @param dataFieldName names of data fields + */ + public void addAxisDataFieldName(String dataFieldName) { + this.axisDataFieldNames.add(dataFieldName); } - public void addDataField(String dataFieldName, Integer defaultAxisDimension, int... dimensionMappings) { - if (defaultWritableDataFieldName == null) { + /** + * Adds the given names to the names of the data fields for this device. Each data field + * will be added to any {@link NXdata} group created for this scan (an {@link NXdata} group is + * created for each primary data field). In order to add a data field that should only + * be added to the {@link NXdata} group for a specific primary data field use + * {@link #addAxisDataFieldForPrimaryDataField(String, String, Integer, int...)} + * @param axisDataFieldNames names of data fields + */ + public void addAxisDataFieldNames(String... axisDataFieldNames) { + this.axisDataFieldNames.addAll(Arrays.asList(axisDataFieldNames)); + } + + /** + * Adds the given data field. This field with this name will be added to any {@link NXdata} + * groups created for this scan. + * @param dataFieldName name of data field + * @param defaultAxisDimension the dimension + * @param dimensionMappings mappings between the dimensions of the data field and the + * primary data field for this device + */ + public void addAxisDataField(String dataFieldName, Integer defaultAxisDimension, int... dimensionMappings) { + if (primaryDataFieldName == null) { throw new IllegalStateException("Default writable data field not set."); } - addDataField(dataFieldName, defaultWritableDataFieldName, defaultAxisDimension, dimensionMappings); + addAxisDataFieldForPrimaryDataField(dataFieldName, primaryDataFieldName, + defaultAxisDimension, dimensionMappings); + } + + /** + * Returns the names of the data fields that are axes for the given primary data field + * within this device. + * @param primaryDataFieldName primary data field name + * @return names of data fields + */ + public List getAxisDataFieldsForPrimaryDataField(String primaryDataFieldName) { + PrimaryDataFieldModel primaryDataFieldModel = getPrimaryDataFieldModel(primaryDataFieldName, false); + if (primaryDataFieldModel == null) { + return Collections.emptyList(); + } + + return primaryDataFieldModel.getAxisFieldNames(); } private PrimaryDataFieldModel getPrimaryDataFieldModel(String primaryDataFieldName, boolean create) { @@ -352,38 +411,41 @@ private PrimaryDataFieldModel getPrimaryDataFieldModel(String primaryDataFieldNa return primaryDataFieldModel; } - public void addDataField(String dataFieldName, String primaryDataFieldName, + /** + * Adds a data field as an axis to a given primary data field. This field is only added + * to the {@link NXdata} group for the given primary data field (i.e. where it is the + * @signal field). + * @param dataFieldName name of data field to add + * @param primaryDataFieldName name of primary data field that the new data field is an axis for + * @param defaultAxisDimension + * @param dimensionMappings (optional) dimension mappings between the new data field + * and the primary data. If this argument is not specified then the dimension mappings will + * be assumed to be {0, 1, 2, etc} if the data field is multidimensional, or + * { defaultAxisDimension } if the data field has a single dimension + */ + public void addAxisDataFieldForPrimaryDataField(String dataFieldName, String primaryDataFieldName, Integer defaultAxisDimension, int... dimensionMappings) { - dataFieldNames.add(dataFieldName); - - // if defaultAxisDimension is set and no dimension mappings are specified - // assume this is a 1 dimensional dataset with mapping the defaultAxisDimension - if (dimensionMappings.length == 0 && defaultAxisDimension != null) { - // TODO can we remove this and make this assumption at a later stage? - dimensionMappings = new int[] { defaultAxisDimension }; - } - PrimaryDataFieldModel primaryDataFieldModel = getPrimaryDataFieldModel(primaryDataFieldName, true); - primaryDataFieldModel.addDataField(dataFieldName, defaultAxisDimension, dimensionMappings); + primaryDataFieldModel.addAxisField(dataFieldName, defaultAxisDimension, dimensionMappings); } - public void addAdditionalPrimaryDataField(String dataFieldName) { + /** + * Add an additional primary data field. This is a data field for which, when this + * device is the primary device in a scan, an additional {@link NXdata} group should be + * created with this field as the @signal field. + * @param dataFieldName the name of the additional primary data field + */ + public void addAdditionalPrimaryDataFieldName(String dataFieldName) { // TODO: is this the best name for this concept? it's a bit confusing // alternatives: addPrimaryDataField, addSecondarySignalField etc - - addDataFields(dataFieldName); // add as a data field if not already added additionalPrimaryDataFieldNames.add(dataFieldName); } - public void addAdditionalPrimaryDataFields(String... dataFieldNames) { - additionalPrimaryDataFieldNames.addAll(Arrays.asList(dataFieldNames)); - } - /* (non-Javadoc) * @see org.eclipse.dawnsci.nexus.builder.NexusObjectProvider#getAdditionalPrimaryDataFieldNames() */ @Override - public List getAdditionalPrimaryDataFields() { + public List getAdditionalPrimaryDataFieldNames() { return additionalPrimaryDataFieldNames; } @@ -417,13 +479,16 @@ public int[] getDimensionMappings(String primaryDataFieldName, String dataFieldN return null; } - public ILazyWriteableDataset getDefaultWriteableDataset() { - final String defaultDataFieldName = getPrimaryDataField(); - return getNexusObject().getLazyWritableDataset(defaultDataFieldName); - } - public ILazyWriteableDataset getWriteableDataset(String fieldName) { return getNexusObject().getLazyWritableDataset(fieldName); } + + public Boolean getUseDeviceNameInNXdata() { + return useDeviceNameInNXdata; + } + + public void setUseDeviceNameInNXdata(boolean useDeviceNameInNXdata) { + this.useDeviceNameInNXdata = useDeviceNameInNXdata; + } } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DataDevice.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DataDevice.java deleted file mode 100644 index 6a8b18cd..00000000 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DataDevice.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.eclipse.dawnsci.nexus.builder; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.dawnsci.nexus.NXdata; -import org.eclipse.dawnsci.nexus.NXobject; -import org.eclipse.dawnsci.nexus.builder.impl.DataFieldDimensionModel; - -/** - * A object of this class wraps an {@link NexusObjectProvider} and contains - * additional information that can be used by a {@link NexusDataBuilder} - * describing how to add the fields for this device to an {@link NXdata} - * group when its {@link NexusDataBuilder#addDevice(DataDevice)} method - * is called. - * - * @author Matthew Dickie - * @param subinterface of {@link NXobject} created by the - * wrapped {@link NexusObjectProvider} - */ -public class DataDevice { - - // TODO add javadoc to methods - - private final NexusObjectProvider nexusObjectProvider; - - private int[] deviceDefaultDimensionMappings = null; - - private boolean useDeviceName; - - private String primaryDataSourceFieldName; - - private Map sourceFields = new LinkedHashMap<>(); - - private Map fieldNameMappings = new HashMap<>(); - - private String defaultAxisSourceFieldName; - - private Integer defaultAxisDimension = null; - - public DataDevice(NexusObjectProvider nexusObjectProvider) { - this(nexusObjectProvider, true, null); - } - - public DataDevice(NexusObjectProvider nexusObjectProvider, boolean useDeviceName) { - this(nexusObjectProvider, useDeviceName, null); - } - - public DataDevice(NexusObjectProvider nexusObjectProvider, - Integer defaultAxisDimension, int... dimensionMappings) { - this(nexusObjectProvider, true, defaultAxisDimension, dimensionMappings); - } - - public DataDevice(NexusObjectProvider nexusObjectProvider, boolean useDeviceName, - Integer defaultAxisDimension, int... dimensionMappings) { - this(nexusObjectProvider, useDeviceName, null, defaultAxisDimension, dimensionMappings); - } - - public DataDevice(NexusObjectProvider nexusObjectProvider, boolean useDeviceName, - String axisFieldName, Integer defaultAxisDimension, int... dimensionMappings) { - this.nexusObjectProvider = nexusObjectProvider; - this.deviceDefaultDimensionMappings = dimensionMappings; - this.useDeviceName = useDeviceName; - this.defaultAxisSourceFieldName = axisFieldName; - this.defaultAxisDimension = defaultAxisDimension; - - if (axisFieldName == null && defaultAxisDimension != null) { - // The default axis dimension applies to the demand field, if there is one - // otherwise it applies to the the default writable data field - String demandDataFieldName = nexusObjectProvider.getDemandDataField(); - if (demandDataFieldName != null) { - this.defaultAxisSourceFieldName = demandDataFieldName; - } else { - this.defaultAxisSourceFieldName = nexusObjectProvider.getPrimaryDataField(); - } - } - - List dataFieldNames = nexusObjectProvider.getDataFields(); - for (String dataFieldName : dataFieldNames) { - sourceFields.put(dataFieldName, null); - } - } - - public NexusObjectProvider getNexusObjectProvider() { - return nexusObjectProvider; - } - - public int[] getDefaultDimensionMappings() { - return deviceDefaultDimensionMappings; - } - - /** - * Set the default dimension mappings for this device. - * @param defaultDimensionMappings - * @return - */ - public DataDevice setDefaultDimensionMappings(int... defaultDimensionMappings) { - this.deviceDefaultDimensionMappings = defaultDimensionMappings; - return this; - } - - public List getSourceFieldNames() { - return new ArrayList<>(sourceFields.keySet()); - } - - public DataDevice clearSourceFields() { - sourceFields.clear(); - fieldNameMappings.clear(); - return this; - } - - public DataDevice setSourceFields(String... sourceFieldNames) { - this.sourceFields.clear(); - for (String sourceField : sourceFieldNames) { - this.sourceFields.put(sourceField, null); - } - return this; - } - - public DataDevice addSourceField(String sourceFieldName) { - this.sourceFields.put(sourceFieldName, null); - return this; - } - - public DataDevice addSourceFields(String... sourceFieldNames) { - for (String sourceFieldName : sourceFieldNames) { - this.sourceFields.put(sourceFieldName, null); - } - return this; - } - - public DataDevice addSourceField(String sourceFieldName, String destinationFieldName) { - sourceFields.put(sourceFieldName, null); - fieldNameMappings.put(sourceFieldName, destinationFieldName); - return this; - } - - public DataDevice addSourceField(String sourceFieldName, Integer defaultAxisDimension, - int... dimensionMappings) { - if (dimensionMappings != null && dimensionMappings.length == 0) { - dimensionMappings = null; - } - - sourceFields.put(sourceFieldName, - new DataFieldDimensionModel(defaultAxisDimension, dimensionMappings)); - return this; - } - - public DataDevice setDestinationFieldName(String sourceFieldName, String destinationFieldName) { - if (!sourceFields.containsKey(sourceFieldName)) { - throw new IllegalArgumentException("Unknown source field: " + sourceFieldName); - } - fieldNameMappings.put(sourceFieldName, destinationFieldName); - return this; - } - - public boolean getUseDeviceName() { - return useDeviceName; - } - - public DataDevice setUseDeviceName(boolean useDeviceName) { - this.useDeviceName = useDeviceName; - return this; - } - - public int[] getDimensionMappings(String sourceFieldName) { - DataFieldDimensionModel fieldInfo = sourceFields.get(sourceFieldName); - if (fieldInfo != null) { - int[] dimensionMappings = fieldInfo.getDimensionMappings(); - if (dimensionMappings != null) { - return dimensionMappings; - } - } - - // use the default dimension mapping for this device - return deviceDefaultDimensionMappings; - } - - public Integer getDefaultAxisDimension(String sourceFieldName) { - DataFieldDimensionModel fieldInfo = sourceFields.get(sourceFieldName); - if (fieldInfo != null) { - return fieldInfo.getDefaultAxisDimension(); - } - if (sourceFieldName.equals(defaultAxisSourceFieldName)) { - return defaultAxisDimension; - } - - return null; - } - - public String getDestinationFieldName(String sourceFieldName) { - String destinationName = fieldNameMappings.get(sourceFieldName); - if (destinationName == null) { - if (useDeviceName) { - if (sourceFields.size() == 1) { - destinationName = nexusObjectProvider.getName(); - } else { - destinationName = nexusObjectProvider.getName() + "_" + sourceFieldName; - } - } else { - destinationName = sourceFieldName; - } - } - - return destinationName; - } - - public String getDefaultAxisSourceFieldName() { - return defaultAxisSourceFieldName; - } - - public void setDefaultAxisSourceFieldName(String defaultAxisSourceFieldName) { - this.defaultAxisSourceFieldName = defaultAxisSourceFieldName; - } - - public Integer getDefaultAxisDimension() { - return defaultAxisDimension; - } - - public void setDefaultAxisDimension(Integer defaultAxisDimension) { - this.defaultAxisDimension = defaultAxisDimension; - } - - public String getSignalDataSourceFieldName() { - if (primaryDataSourceFieldName != null) { - return primaryDataSourceFieldName; - } - - // by default use default writable data field as primary (@signal) data field - return nexusObjectProvider.getPrimaryDataField(); - } - - public void setPrimaryDataSourceFieldName(String primaryDataSourceFieldName) { - this.primaryDataSourceFieldName = primaryDataSourceFieldName; - } - -} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DelegateNexusProvider.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DelegateNexusProvider.java index 1d6b7154..27c5e5d7 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DelegateNexusProvider.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/DelegateNexusProvider.java @@ -7,40 +7,30 @@ import org.eclipse.dawnsci.nexus.NexusNodeFactory; import org.eclipse.dawnsci.nexus.NexusScanInfo; - /** - * Use this concrete class to make a given class implement INexusDevice properly. + * Use this concrete class to make a given class implement INexusDevice + * properly. * * @author Matthew Gerring * * @param */ -public class DelegateNexusProvider extends AbstractNexusProvider { - +public class DelegateNexusProvider extends AbstractNexusObjectProvider { + private INexusDevice creator; private NexusScanInfo info; - public DelegateNexusProvider(NexusBaseClass nexusBaseClass, NexusScanInfo info, INexusDevice creator) { - super(nexusBaseClass); - this.info = info; - this.creator = creator; - } - - public DelegateNexusProvider(String name, NexusBaseClass nexusBaseClass, String defaultDataFieldName, NexusBaseClass category, NexusScanInfo info, INexusDevice creator) { - super(name, nexusBaseClass, category, defaultDataFieldName); - this.info = info; + public DelegateNexusProvider(String name, NexusBaseClass nexusBaseClass, NexusScanInfo info, + INexusDevice creator) { + super(name, nexusBaseClass); + this.info = info; this.creator = creator; } - public DelegateNexusProvider(String name, NexusBaseClass nexusBaseClass, String defaultDataFieldName, NexusScanInfo info, INexusDevice creator) { + public DelegateNexusProvider(String name, NexusBaseClass nexusBaseClass, + String defaultDataFieldName, NexusScanInfo info, INexusDevice creator) { super(name, nexusBaseClass, defaultDataFieldName); - this.info = info; - this.creator = creator; - } - - public DelegateNexusProvider(String name, NexusBaseClass nexusBaseClass, NexusScanInfo info, INexusDevice creator) { - super(name, nexusBaseClass); - this.info = info; + this.info = info; this.creator = creator; } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusEntryBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusEntryBuilder.java index a4bf678c..3b6dc326 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusEntryBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusEntryBuilder.java @@ -26,6 +26,7 @@ import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; import org.eclipse.dawnsci.nexus.builder.appdef.NexusApplicationBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.dawnsci.nexus.impl.NXentryImpl; import org.eclipse.dawnsci.nexus.validation.NexusValidationException; diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusObjectProvider.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusObjectProvider.java index c039171f..51287994 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusObjectProvider.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusObjectProvider.java @@ -22,6 +22,7 @@ import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; /** * Defines the interface for a class that can create a a NeXus object of a particular type. @@ -44,7 +45,7 @@ public interface NexusObjectProvider extends NexusEntryModif /** * Return the NeXus base class enum value for the type NeXus object this * provider creates. - * @return + * @return the {@link NexusBaseClass} for this object provider */ public NexusBaseClass getNexusBaseClass(); @@ -58,7 +59,9 @@ public interface NexusObjectProvider extends NexusEntryModif /** * Returns the nexus object, creating it if necessary - * @param createIfNecessary + * @param nodeFactory node factory to create the nexus object + * @param createIfNecessary true to create the nexus object if necessary, + * false otherwise * @return nexus object * @throws NexusException if the nexus object could not be created for any reason */ @@ -70,7 +73,6 @@ public interface NexusObjectProvider extends NexusEntryModif * otherwise returns null. This method should not return a new * NeXus object each time. * @return NeXus object or null - * @throws NexusException if the nexus object could not be created for any reason */ public N getNexusObject(); @@ -104,12 +106,21 @@ public interface NexusObjectProvider extends NexusEntryModif // methods below this line are relevant only when adding this object to a NexusDataBuilder /** - * Returns the data field names for this object. These are the fields + * Returns the axis data field names for this object. These are the fields * that will be linked to when this this object is added to * an {@link NexusDataBuilder} to construct an {@link NXdata} group. + * + * This method should not return the names of primary data fields, nor should it + * return the names of data fields which should only be added to the {@link NXdata} groups + * for a particular primary data field (an {@link NXdata} group is added to the scan for + * each primary data field, as returned by {@link #getPrimaryDataFieldName()} and + * {@link #getAdditionalPrimaryDataFieldNames()}). The primary data field will also be linked + * to in an {@link NXdata} group, except where this device is the primary device for the scan + * where it is not linked to in the {@link NXdata} groups for additional primary data fields. + * * @return name of data fields for this object */ - public List getDataFields(); + public List getAxisDataFieldNames(); /** * Returns the name of the default data field to write to within the nexus object. @@ -117,31 +128,42 @@ public interface NexusObjectProvider extends NexusEntryModif * this is the field name of the default field, i.e. the field referred to by * the @signal attribute. *

- * If this object has more than one field for an NXdata should be created, - * these can be + * If additional {@link NXdata} groups should be created for other fields in this scan, + * then the names of these fields should be returned by {@link #getAdditionalPrimaryDataFieldNames()}. * * @return default data field name, this cannot be null */ - public String getPrimaryDataField(); + public String getPrimaryDataFieldName(); /** * Returns the names of any additional primary data fields for this device. * This method indicates that if this device is to be used to create an - * {@link NXdata} with the field {@link #getPrimaryDataField()} + * {@link NXdata} with the field {@link #getPrimaryDataFieldName()} * as the default (signal field), then additional {@link NXdata} groups * should be created for each of these fields. * * @return additional primary data field names */ - public List getAdditionalPrimaryDataFields(); + public List getAdditionalPrimaryDataFieldNames(); + + /** + * Returns the names of any data fields that are axes for the primary data field with + * the given name. These data fields are those that should be added to the {@link NXdata} + * group for the primary data field with the given name (and not those for other primary + * data fields), in addition to the data fields returned by {@link #getAxisDataFieldNames()} + * @param primaryDataFieldName primary data field name + * @return names of data fields + */ + public List getAxisDataFieldsForPrimaryDataField(String primaryDataFieldName); /** - * Returns the name of the demand field for this nexus object, if any. - * If this object is added as a device to an {@link NXdata}, then this - * is the field that will be added as an axis of the default dataset. + * Returns the name of the default axis field for this nexus object, if any. + * If this object is added as a device to an {@link NXdata} then this + * is the field that will be added as a default axis of the @signal field, + * for example for a positioner this may be the demand field. * @return name of demand field, or null if none. */ - public String getDemandDataField(); + public String getDefaultAxisDataFieldName(); /** * Returns the dimension of the given primary data field for which the data field with the @@ -150,22 +172,36 @@ public interface NexusObjectProvider extends NexusEntryModif * This method is required only when this device provides the default data field * of an {@link NXdata} group (i.e. that referred to by the @signal attribute), * and additional data fields within this device provide default axis for that data field + * @param primaryDataFieldName name of primary data field + * @param dataFieldName data field * @return dimension of the default data field for which the field with the * given name provides a default axis, or null if none */ public Integer getDefaultAxisDimension(String primaryDataFieldName, String dataFieldName); /** - * Returns the dimension mappings between the data field and + * Returns the dimension mappings between the data field and * the primary data field with the given names. * This method is required only when this device provides the default data * field of an {@link NXdata} group (i.e. that referred to by the signal * attribute), and additional data fields within that * and the default data field of this device. - * @param fieldName field name + * @param primaryDataFieldName field name + * @param dataFieldName data field name * @return dimension mappings between the field with the given name and the * default data field */ public int[] getDimensionMappings(String primaryDataFieldName, String dataFieldName); + /** + * Returns whether the names of the fields within the nexus object should be prefixed with the + * device name when linked to from an {@link NXdata} group. If this method returns + * true and just one data field + * from this device is added to the {@link NXdata}, then the device name will be used as the + * name of the field. + * @return true to use the device name when linking fields in an {@link NXdata} + * group, false to not use the device name, null unspecified + */ + public Boolean getUseDeviceNameInNXdata(); + } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/NexusApplicationBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/NexusApplicationBuilder.java index 839b6b3d..5fcfc6d8 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/NexusApplicationBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/NexusApplicationBuilder.java @@ -16,8 +16,8 @@ import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NXsubentry; import org.eclipse.dawnsci.nexus.NexusException; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.dawnsci.nexus.impl.NXsubentryImpl; import org.eclipse.dawnsci.nexus.validation.NexusValidationException; diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/PredeterminedLinksApplicationDataBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/PredeterminedLinksApplicationDataBuilder.java index d7529b94..9d38e1e0 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/PredeterminedLinksApplicationDataBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/PredeterminedLinksApplicationDataBuilder.java @@ -14,13 +14,15 @@ import org.eclipse.dawnsci.analysis.api.tree.DataNode; import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NXsubentry; import org.eclipse.dawnsci.nexus.NexusException; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.appdef.NexusApplicationBuilder; -import org.eclipse.dawnsci.nexus.builder.impl.AbstractNexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.AxisDataDevice; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.PrimaryDataDevice; +import org.eclipse.dawnsci.nexus.builder.data.impl.AbstractNexusDataBuilder; /** * A data builder, wrapping an {@link NXdata} base class instance, within an application definition where @@ -31,7 +33,7 @@ * for an application definition where the NeXus application definition specifies links for the * locations. NXtomo is an example of this. * when its {@link NexusApplicationBuilder#newData()} method is invoked. It should then add - * the appropriate links using the {@link #addLink(String, String)} method of this class. + * the appropriate links using the {@link #addLink(String, DataNode)} method of this class. */ public class PredeterminedLinksApplicationDataBuilder extends AbstractNexusDataBuilder implements NexusDataBuilder { @@ -55,22 +57,21 @@ protected void addLink(final String name, final DataNode dataNode) throws NexusE } @Override - public void setPrimaryDevice(DataDevice primaryDeviceModel) + public void setPrimaryDevice(PrimaryDataDevice primaryDeviceModel) throws NexusException { // this data model already has all the information it needs to be fully populated throw new UnsupportedOperationException("No additional objects are required for this data model"); } @Override - public void addDataDevice(NexusObjectProvider dataDevice, - Integer defaultAxisDimension, int... dimensionMappings) - throws NexusException { + public void addAxisDevice(NexusObjectProvider dataDevice, + Integer defaultAxisDimension, int... dimensionMappings) throws NexusException { // this data model already has all the information it needs to be fully populated throw new UnsupportedOperationException("No additional objects are required for this data model"); } @Override - public void addDataDevice(DataDevice dataDeviceModel) + public void addAxisDevice(AxisDataDevice dataDeviceModel) throws NexusException { // this data model already has all the information it needs to be fully populated throw new UnsupportedOperationException("No additional objects are required for this data model"); diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilder.java index b48a7878..623be9f8 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/appdef/impl/TomoApplicationBuilder.java @@ -28,10 +28,10 @@ import org.eclipse.dawnsci.nexus.NexusApplicationDefinition; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.appdef.NexusApplicationBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.dawnsci.nexus.validation.NXtomoValidator; import org.eclipse.dawnsci.nexus.validation.NexusValidationException; @@ -145,7 +145,7 @@ public void setRotationAngle(NexusObjectProvider rotationAnglePosi /** * Sets the rotation angle - * @param rotationAnglePositioner rotation angle data node + * @param rotationAngle rotation angle data node * @throws NexusException */ public void setRotationAngle(DataNode rotationAngle) throws NexusException { @@ -271,7 +271,7 @@ protected void addPredeterminedLinks(PredeterminedLinksApplicationDataBuilder da private DataNode getDataNode(NexusObjectProvider nexusObjectProvider) throws NexusException { final N nexusObject = nexusObjectProvider.getNexusObject(getNexusNodeFactory(), true); - final String dataNodeName = nexusObjectProvider.getPrimaryDataField(); + final String dataNodeName = nexusObjectProvider.getPrimaryDataFieldName(); final DataNode dataNode = nexusObject.getDataNode(dataNodeName); if (dataNode == null) { throw new NexusException(MessageFormat.format("No such data node for {0} with name ''{1}''", diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/AxisDataDevice.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/AxisDataDevice.java new file mode 100644 index 00000000..8683fe1b --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/AxisDataDevice.java @@ -0,0 +1,26 @@ +package org.eclipse.dawnsci.nexus.builder.data; + +import org.eclipse.dawnsci.nexus.NXobject; + +/** + * Axis data device. + * @author wgp76868 + * + * @param + */ +public interface AxisDataDevice extends DataDevice { + + // no additional methods, this interface exists only for type safety + + /** + * Overrides the {@link DataDevice#isPrimary()} to return true always, as this + * is a primary device. + * + * @see org.eclipse.dawnsci.nexus.builder.data.DataDevice#isPrimary() + * @return true, always + */ + public default boolean isPrimary() { + return false; + } + +} \ No newline at end of file diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDevice.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDevice.java new file mode 100644 index 00000000..65e9bc94 --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDevice.java @@ -0,0 +1,90 @@ +package org.eclipse.dawnsci.nexus.builder.data; + +import java.util.List; + +import org.eclipse.dawnsci.analysis.api.tree.DataNode; +import org.eclipse.dawnsci.analysis.api.tree.Node; +import org.eclipse.dawnsci.analysis.api.tree.SymbolicNode; +import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; + +/** + * Represents a device which can be added to an {@link NexusDataBuilder} to build an + * {@link NXdata} group. It may wrap on otherwise be constructed from an instance of a + * sub-interface of {@link NXobject}. The method {@link #getFieldNode(String)} should return + * the node with the given name from the. + *

+ * This is an abstract interface. Any class which implements this interface should also implement + * either {@link PrimaryDataDevice} (which sh + * + * @param the sub-interface of {@link NXobject} that the nexus object was created from + * + * @author Matthew Dickie + */ +public interface DataDevice { + + /** + * Returns whether this is the primary device for the {@link NXdata} group being built. + * This primary device is the device which contains the @signal field for + * the {@link NXdata} group. + * @return true if this is the primary device, false otherwise + */ + public boolean isPrimary(); + + /** + * Returns the nexus object for this data device. + * @return nexus object + */ + public N getNexusObject(); + + /** + * Returns the list of the axis field names. + * @return axis field names + */ + public List getAxisFieldNames(); + + /** + * Returns the {@link Node} for the field with the given name in the {@link NXobject} + * that this object was created from. In most cases this will be + * a {@link DataNode}, but may be a {@link SymbolicNode} in the case of an external link + * @param sourceFieldName field name in the existing {@link NXobject} + * @return the node with the given name + */ + public Node getFieldNode(String sourceFieldName); + + /** + * Returns the rank of the source field with the given name + * @param sourceFieldName field name in the existing {@link NXobject} + * @return rank of the field with the given name + */ + public int getFieldRank(String sourceFieldName); + + /** + * Returns the name that the field with the given name in the {@link NXobject} should be + * given in the {@link NXdata} group when added (i.e. linked to). + * @param sourceFieldName field name in the existing {@link NXobject} + * @return destination name + */ + public String getDestinationFieldName(String sourceFieldName); + + /** + * Returns the dimension mappings for the field with the given name. This is an array of + * integers each of which specifies the index of the @signal field that + * the dimension of the dataset for this field name with the corresponding index maps to. + * @param sourceFieldName field name in the existing {@link NXobject} + * @return dimension mappings between the field with the given name and the + * @signal field of the {@link NXdata} group + */ + public int[] getDimensionMappings(String sourceFieldName); + + /** + * Returns the index of the dimension of the @signal field of the {@link NXdata} + * group the field of the {@link NXobject} with the given name is a default axis for, or + * null if this field is not a default axis of the @signal field. + * @param sourceFieldName field name in the existing {@link NXobject} + * @return dimension of the signal field that this field is a default axis for, + * or null + */ + public Integer getDefaultAxisDimension(String sourceFieldName); + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDeviceBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDeviceBuilder.java new file mode 100644 index 00000000..48dbc15a --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/DataDeviceBuilder.java @@ -0,0 +1,456 @@ +package org.eclipse.dawnsci.nexus.builder.data; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.dawnsci.analysis.api.tree.DataNode; +import org.eclipse.dawnsci.analysis.api.tree.Node; +import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; +import org.eclipse.dawnsci.nexus.NexusException; +import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.impl.AxisDataDeviceImpl; +import org.eclipse.dawnsci.nexus.builder.data.impl.AxisFieldModel; +import org.eclipse.dawnsci.nexus.builder.data.impl.DataDeviceImpl; +import org.eclipse.dawnsci.nexus.builder.data.impl.DataFieldModel; +import org.eclipse.dawnsci.nexus.builder.data.impl.PrimaryDataDeviceImpl; + +/** + * A builder class for building a {@link DataDevice} from an {@link NexusObjectProvider}. + * Provides the ability to configure which fields from the underlying nexus object are + * are linked to the {@link NXdata} group and how. + * + * @author Matthew Dickie + * + * @param the sub-interface of {@link NXobject} that the nexus object was created from + */ +public class DataDeviceBuilder { + + public static PrimaryDataDevice newPrimaryDataDevice( + NexusObjectProvider nexusObjectProvider) throws NexusException { + return (PrimaryDataDevice) newPrimaryDataDeviceBuilder(nexusObjectProvider).build(); + } + + public static PrimaryDataDevice newPrimaryDataDevice( + NexusObjectProvider nexusObjectProvider, String signalDataFieldName) throws NexusException { + DataDeviceBuilder builder = new DataDeviceBuilder<>(nexusObjectProvider, true); + builder.setSignalField(signalDataFieldName); + return (PrimaryDataDevice) builder.build(); + } + + public static DataDeviceBuilder newPrimaryDataDeviceBuilder( + NexusObjectProvider nexusObjectProvider) { + return new DataDeviceBuilder<>(nexusObjectProvider, true); + } + + public static AxisDataDevice newAxisDataDevice( + NexusObjectProvider nexusObjectProvider) throws NexusException { + return (AxisDataDevice) newAxisDataDeviceBuilder(nexusObjectProvider).build(); + } + + public static AxisDataDevice newAxisDataDevice( + NexusObjectProvider nexusObjectProvider, Integer defaultAxisDimension) throws NexusException { + return (AxisDataDevice) newAxisDataDeviceBuilder(nexusObjectProvider, defaultAxisDimension).build(); + } + + public static AxisDataDevice newAxisDataDevice( + NexusObjectProvider nexusObjectProvider, String defaultAxisSourceFieldName, + Integer defaultAxisDimension) throws NexusException { + return (AxisDataDevice) newAxisDataDeviceBuilder(nexusObjectProvider, + defaultAxisSourceFieldName, defaultAxisDimension).build(); + } + + public static DataDeviceBuilder newAxisDataDeviceBuilder( + NexusObjectProvider nexusObjectProvider) { + return new DataDeviceBuilder<>(nexusObjectProvider, false); + } + + public static DataDeviceBuilder newAxisDataDeviceBuilder( + NexusObjectProvider nexusObjectProvider, Integer defaultAxisDimension) { + DataDeviceBuilder builder = new DataDeviceBuilder<>(nexusObjectProvider, false); + builder.setDefaultAxisDimension(defaultAxisDimension); + return builder; + } + + public static DataDeviceBuilder newAxisDataDeviceBuilder( + NexusObjectProvider nexusObjectProvider, String defaultAxisSourceFieldName, + Integer defaultAxisDimension) { + DataDeviceBuilder builder = new DataDeviceBuilder<>(nexusObjectProvider, false); + builder.setDefaultAxisSourceFieldName(defaultAxisSourceFieldName); + builder.setDefaultAxisDimension(defaultAxisDimension); + return builder; + } + + private final boolean isPrimary; + + private final NexusObjectProvider nexusObjectProvider; + + private final N nexusObject; + + private String signalFieldSourceName = null; + + private boolean includeAddedFieldsOnly = false; + + private List addedFields = null; + + private Integer defaultAxisDimension = null; + + private String defaultAxisSourceFieldName = null; + + private Map overriddenDestinationFieldNames = null; + + private Map overriddenDefaultAxisDimensions = null; + + private Map overriddenDimensionMappings = null; + + private int[] defaultDimensionMappings = null; + + private Boolean useDeviceName = null; + + private String destinationFieldNamePrefix = null; + + private int numberOfAxisFieldsToAdd; + + /** + * Create a new {@link DataDeviceBuilder} for the given {@link NexusObjectProvider}. + * + * @param nexusObjectProvider nexus object provider wrapping a {@link NXobject} + * @param isPrimary true to build a {@link PrimaryDataDevice}, containing + * the @signal field for the {@link NXdata} group, + * false to build an {@link AxisDataDevice}. + */ + public DataDeviceBuilder(NexusObjectProvider nexusObjectProvider, boolean isPrimary) { + Objects.requireNonNull(nexusObjectProvider); + this.nexusObjectProvider = nexusObjectProvider; + this.nexusObject = nexusObjectProvider.getNexusObject(); + Objects.requireNonNull(nexusObject); + this.isPrimary = isPrimary; + + if (isPrimary) { + signalFieldSourceName = nexusObjectProvider.getPrimaryDataFieldName(); + Objects.requireNonNull(signalFieldSourceName); + } + } + + public void setSignalField(String signalFieldSourceName) { + Objects.requireNonNull(signalFieldSourceName, "The signal field of an NXdata group cannot be null. Probably you have not set a primary data field for your nexus object."); + this.signalFieldSourceName = signalFieldSourceName; + } + + public void clearAxisFields() { + addedFields = null; + includeAddedFieldsOnly = true; + } + + public void addAxisField(String axisFieldName) { + Objects.requireNonNull(axisFieldName); + if (addedFields == null) { + addedFields = new ArrayList<>(); + } + addedFields.add(axisFieldName); + } + + public void addAxisField(String axisFieldName, int defaultAxisDimension) { + addAxisField(axisFieldName); + setDefaultAxisDimension(axisFieldName, defaultAxisDimension); + } + + public void addAxisField(String axisFieldName, String axisFieldDestinationName) { + addAxisField(axisFieldName); + setDestinationFieldName(axisFieldName, axisFieldDestinationName); + } + + public void setDefaultAxisDimension(String axisFieldName, int defaultAxisDimension) { + Objects.requireNonNull(axisFieldName); + if (overriddenDefaultAxisDimensions == null) { + overriddenDefaultAxisDimensions = new HashMap<>(); + } + overriddenDefaultAxisDimensions.put(axisFieldName, defaultAxisDimension); + } + + public void addAxisField(String axisFieldName, int[] dimensionMappings) { + addAxisField(axisFieldName); + setDimensionMappings(axisFieldName, dimensionMappings); + } + + public void setDimensionMappings(String axisFieldName, int... dimensionMappings) { + Objects.requireNonNull(axisFieldName); + if (overriddenDimensionMappings == null) { + overriddenDimensionMappings = new HashMap<>(); + } + + overriddenDimensionMappings.put(axisFieldName, dimensionMappings); + } + + public void addAxisFields(String... axisFieldNames) { + for (String axisFieldName : axisFieldNames) { + addAxisField(axisFieldName); + } + } + + public void setAxisFields(String... axisFieldNames) { + clearAxisFields(); + addAxisFields(axisFieldNames); + } + + public void setDefaultAxisDimension(Integer defaultAxisDimension) { + this.defaultAxisDimension = defaultAxisDimension; + } + + public void setDefaultAxisSourceFieldName(String defaultAxisSourceFieldName) { + Objects.requireNonNull(defaultAxisSourceFieldName); + addAxisField(defaultAxisSourceFieldName); + this.defaultAxisSourceFieldName = defaultAxisSourceFieldName; + } + + public void setDefaultDimensionMappings(int[] defaultDimensionMappings) { + this.defaultDimensionMappings = defaultDimensionMappings; + } + + public void setUseDeviceName(boolean useDeviceName) { + this.useDeviceName = useDeviceName; + } + + public void setDestinationFieldNamePrefix(String prefix) { + destinationFieldNamePrefix = prefix; + } + + public void setDestinationFieldName(String sourceFieldName, String destinationFieldName) { + Objects.requireNonNull(sourceFieldName); + Objects.requireNonNull(destinationFieldName); + if (overriddenDestinationFieldNames == null) { + overriddenDestinationFieldNames = new HashMap<>(); + } + overriddenDestinationFieldNames.put(sourceFieldName, destinationFieldName); + } + + private DataDeviceImpl createDataDevice() throws NexusException { + N nexusObject = nexusObjectProvider.getNexusObject(); + if (isPrimary) { + DataFieldModel signalFieldModel = createSignalFieldModel(); + return new PrimaryDataDeviceImpl(nexusObject, signalFieldModel); + } + + return new AxisDataDeviceImpl(nexusObject); + } + + /** + * Get the rank of the field with the given name . + * @param fieldName field name + * @return field rank + * @throws NexusException + */ + private int getFieldRank(String fieldName) throws NexusException { + final Node fieldNode = nexusObject.getNode(fieldName); + if (fieldNode != null) { + // the node is a data node + if (fieldNode.isDataNode()) { + return ((DataNode) fieldNode).getRank(); + } + + // the node is an external link. The rank should have been set in the NexusObjectProvider + if (fieldNode.isSymbolicNode()) { + return nexusObjectProvider.getExternalDatasetRank(fieldName); + } + } + + // no such data node or external link + throw new NexusException(MessageFormat.format( + "The {0} does not have a data node or symbolic node with the name: {1}", + nexusObject.getNXclass().getSimpleName(), fieldName)); + } + + private Integer getDefaultAxisDimension(String axisFieldName) { + Integer defaultAxisDimension = null; + + // first check if the value has been overridden (i.e. explicitly set) + if (overriddenDefaultAxisDimensions != null) { + defaultAxisDimension = overriddenDefaultAxisDimensions.get(axisFieldName); + } + + // if this is the default axis field, apply the default axis dimension + if (defaultAxisDimension == null && axisFieldName.equals(defaultAxisSourceFieldName)) { + defaultAxisDimension = this.defaultAxisDimension; + } + + // for a primary device, see if the nexus object provider knows the default axis dimension + // e.g. the axis field belongs to the same device as the signal field for the NXdata + if (defaultAxisDimension == null && isPrimary) { + defaultAxisDimension = nexusObjectProvider.getDefaultAxisDimension( + signalFieldSourceName, axisFieldName); + } + + return defaultAxisDimension; + } + + private int[] getDimensionMappings(String axisFieldName) throws NexusException { + int[] dimensionMappings = null; + + // first check if the value has been overridden (i.e. explicitly set) + if (overriddenDimensionMappings != null) { + dimensionMappings = overriddenDimensionMappings.get(axisFieldName); + } + + // if this is a default axis field and has size 1, this must be the dimension mapping + final int fieldRank = getFieldRank(axisFieldName); + if (dimensionMappings == null && fieldRank == 1) { + Integer defaultAxisDimensions = getDefaultAxisDimension(axisFieldName); + if (defaultAxisDimensions != null) { + dimensionMappings = new int[] { defaultAxisDimensions.intValue() }; + } + } + + // use the default dimension mappings for the device if set and of the same rank + if (dimensionMappings == null && defaultDimensionMappings != null && + fieldRank == defaultDimensionMappings.length) { + dimensionMappings = defaultDimensionMappings; + } + + return dimensionMappings; + } + + private String getDestinationFieldName(String sourceFieldName) { + String destinationFieldName = null; + + // first check if the value has been overridden (i.e. explicitly set) + if (overriddenDestinationFieldNames != null && + overriddenDestinationFieldNames.containsKey(sourceFieldName)) { + return overriddenDestinationFieldNames.get(sourceFieldName); + } + + // if a destination name prefix has been set, use that + if (destinationFieldName == null && destinationFieldNamePrefix != null) { + return destinationFieldNamePrefix + destinationFieldName; + } + + if (useDeviceName()) { + String deviceName = nexusObjectProvider.getName(); + // if there's just one field, use the device name as the destination field name + if (getNumberOfFieldsToAdd() == 1) { + destinationFieldName = deviceName; + } else { + // otherwise prepend the device name to the source field name + destinationFieldName = deviceName + '_' + sourceFieldName; + } + } else { + destinationFieldName = sourceFieldName; + } + + return destinationFieldName; + } + + private boolean useDeviceName() { + if (useDeviceName != null) { + return useDeviceName.booleanValue(); + } + + if (nexusObjectProvider.getUseDeviceNameInNXdata() != null) { + return nexusObjectProvider.getUseDeviceNameInNXdata(); + } + + return !isPrimary; + } + + private int getNumberOfFieldsToAdd() { + return numberOfAxisFieldsToAdd + (isPrimary ? 1 : 0); + } + + private DataFieldModel createSignalFieldModel() throws NexusException { + int fieldRank = getFieldRank(signalFieldSourceName); + String signalDestFieldName = getDestinationFieldName(signalFieldSourceName); + DataFieldModel signalFieldModel = new DataFieldModel(signalFieldSourceName, signalDestFieldName, fieldRank); + + return signalFieldModel; + } + + /** + * Creates and returns the {@link AxisFieldModel} for the field with the given name. + * @param axisFieldName axis field name + * @return axis field model + * @throws NexusException + */ + private AxisFieldModel createAxisFieldModel(String axisFieldName) throws NexusException { + Integer defaultAxisDimension = getDefaultAxisDimension(axisFieldName); + int[] dimensionMappings = getDimensionMappings(axisFieldName); + String destinationFieldName = getDestinationFieldName(axisFieldName); + int rank = getFieldRank(axisFieldName); + + final AxisFieldModel axisFieldModel = new AxisFieldModel(axisFieldName, rank); + axisFieldModel.setDefaultAxisDimension(defaultAxisDimension); + axisFieldModel.setDimensionMappings(dimensionMappings); + axisFieldModel.setDestinationFieldName(destinationFieldName); + + return axisFieldModel; + } + + private Set calculateAxisFieldNamesToAdd() { + Set axisFieldNames = new LinkedHashSet<>(); + + if (!includeAddedFieldsOnly) { + // add the default fields according to the nexus object provider + + if (isPrimary) { + // add any axis fields specific to this primary data field (i.e. signal field) + axisFieldNames.addAll(nexusObjectProvider.getAxisDataFieldsForPrimaryDataField( + signalFieldSourceName)); + } else { + // if this is not a primary device, the primary data field of the + // nexus object provider is an axis field for the signal field + // (which is from the primary device) + axisFieldNames.add(nexusObjectProvider.getPrimaryDataFieldName()); + } + if (nexusObjectProvider.getDefaultAxisDataFieldName() != null) { + axisFieldNames.add(nexusObjectProvider.getDefaultAxisDataFieldName()); + } + axisFieldNames.addAll(nexusObjectProvider.getAxisDataFieldNames()); + } + + // add the fields added by calling addAxisField() + if (addedFields != null) { + axisFieldNames.addAll(addedFields); + } + + if (isPrimary) { + // make sure the signal field name isn't included + axisFieldNames.remove(signalFieldSourceName); + } + + return axisFieldNames; + } + + /** + * Builds and returns the data device. If primary was set to true, a + * {@link PrimaryDataDevice} will be returned, otherwise an {@link AxisDataDevice} will be + * returned + * @return data device + * @throws NexusException + */ + public DataDevice build() throws NexusException { + final DataDeviceImpl dataDevice = createDataDevice(); + + // calculate the default axis source field name, if not set + if (defaultAxisSourceFieldName == null && defaultAxisDimension != null) { + defaultAxisSourceFieldName = nexusObjectProvider.getDefaultAxisDataFieldName(); + if (defaultAxisSourceFieldName == null) { + defaultAxisSourceFieldName = nexusObjectProvider.getPrimaryDataFieldName(); + } + } + + // get the names of the axis fields to add + Set axisFieldNames = calculateAxisFieldNamesToAdd(); + numberOfAxisFieldsToAdd = axisFieldNames.size(); + for (String axisFieldName : axisFieldNames) { + AxisFieldModel axisFieldModel = createAxisFieldModel(axisFieldName); // add each field + dataDevice.addAxisField(axisFieldModel); + } + + return dataDevice; + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusDataBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/NexusDataBuilder.java similarity index 68% rename from org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusDataBuilder.java rename to org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/NexusDataBuilder.java index 01cef87c..a285bf1c 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/NexusDataBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/NexusDataBuilder.java @@ -10,21 +10,21 @@ * Matthew Dickie - initial API and implementation and/or initial documentation *******************************************************************************/ -package org.eclipse.dawnsci.nexus.builder; +package org.eclipse.dawnsci.nexus.builder.data; import org.eclipse.dawnsci.analysis.api.tree.DataNode; import org.eclipse.dawnsci.nexus.NXdata; import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NexusException; +import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; import org.eclipse.dawnsci.nexus.impl.NXdataImpl; /** - * Wraps a {@link NXdataImpl} object and adds methods to configure it by adding - * {@link NexusObjectProvider}s providing the data node and and axis data. - * + * Wraps a {@link NXdataImpl} object and provides methods to configure it by adding + * {@link NexusObjectProvider}s providing the data node and axis data. */ public interface NexusDataBuilder { - + public static final String NO_DEFAULT_AXIS_PLACEHOLDER = "."; public static final String ATTR_NAME_SIGNAL = "signal"; @@ -48,17 +48,17 @@ public interface NexusDataBuilder { /** * Sets the given device as the primary device of the wrapped {@link NXdata} * group. The data node of the device with the name as returned by - * {@link NexusObjectProvider#getPrimaryDataField()} will be set + * {@link NexusObjectProvider#getPrimaryDataFieldName()} will be set * as the default data field of this device, (referenced by the * @signal other fields as returned by - * {@link NexusObjectProvider#getDataFields()} will also be added. + * {@link NexusObjectProvider#getAxisDataFieldNames()} will also be added. * * @param primaryDevice * primary device * @throws NexusException * if the device could not be added for any reason */ - public void setPrimaryDevice(NexusObjectProvider primaryDevice) + public void setPrimaryDevice(NexusObjectProvider primaryDevice) throws NexusException; /** @@ -75,58 +75,31 @@ public void setPrimaryDevice(NexusObjectProvider primaryDevice) * @throws NexusException * if the device could not be added for any reason */ - public void setPrimaryDevice(DataDevice primaryDeviceModel) - throws NexusException; - - /** - * Adds the data fields of the given device to the wrapped {@link NXdata} - * group. - * - * @param dataDevice - * device - * @throws NexusException - * if the device could not be added for any reason - */ - public void addDataDevice(NexusObjectProvider dataDevice) + public void setPrimaryDevice(PrimaryDataDevice primaryDeviceModel) throws NexusException; /** * Adds the data fields of the given device to the wrapped {@link NXdata} * group. The fields do add are determined by - * {@link NexusObjectProvider#getDataFields()}. - *

- * Additionally the field with the name as returned by - * {@link NexusObjectProvider#getDemandDataField()}, or by - * {@link NexusObjectProvider#getPrimaryDataField()} if the - * former is null is set as the default axis of the main data - * field of the {@link NXdata} for the dimension with the given index (e.g. - * the value of the @axes attribute at that index is set to the - * name of this field). + * {@link NexusObjectProvider#getAxisDataFieldNames()}. *

- * The dimension mappings for each field are set to those of the scan, e.g. - * each data field maps to the dimension of the default data field of the - * {@link NXdata} section with the same index. * * @param dataDevice - * data device - * @param defaultAxisDimension - * the index of the axis of the main data field of the wrapped - * {@link NXdata} for which this device provides a default axis - * value + * device * @throws NexusException * if the device could not be added for any reason */ - public void addDataDevice(NexusObjectProvider dataDevice, - int defaultAxisDimension) throws NexusException; + public void addAxisDevice(NexusObjectProvider dataDevice) + throws NexusException; /** * Adds the data fields of the given device to the wrapped {@link NXdata} * group. The fields do add are determined by - * {@link NexusObjectProvider#getDataFields()}. + * {@link NexusObjectProvider#getAxisDataFieldNames()}. *

* Additionally the field with the name as returned by - * {@link NexusObjectProvider#getDemandDataField()}, or by - * {@link NexusObjectProvider#getPrimaryDataField()} if the + * {@link NexusObjectProvider#getDefaultAxisDataFieldName()}, or by + * {@link NexusObjectProvider#getPrimaryDataFieldName()} if the * former is null is set as the default axis of the main data * field of the {@link NXdata} for the dimension with the given index (e.g. * the value of the @axes attribute at that index is set to the @@ -143,10 +116,12 @@ public void addDataDevice(NexusObjectProvider dataDevice, * the index of the axis of the main data field of the wrapped * {@link NXdata} for which this device provides a default axis * value + * @param dimensionMappings dimension mappings between the data field(s) of the device + * and the @signal field of the {@link NXdata} group * @throws NexusException * if the device could not be added for any reason */ - public void addDataDevice(NexusObjectProvider dataDevice, + public void addAxisDevice(NexusObjectProvider dataDevice, Integer defaultAxisDimension, int... dimensionMappings) throws NexusException; @@ -156,14 +131,13 @@ public void addDataDevice(NexusObjectProvider dataDevice, * {@link NexusObjectProvider} and provides methods for configuring how the * {@link DataNode}s for the device should be added to the {@link NXdata} * - * @param primaryDeviceModel + * @param dataDeviceModel * a {@link DataDevice} wrapping the {@link NexusObjectProvider} * that provides the {@link NXobject} whose fields should be * added to the {@link NXdata} * @throws NexusException * if the device could not be added for any reason */ - public void addDataDevice(DataDevice dataDeviceModel) - throws NexusException; + public void addAxisDevice(AxisDataDevice dataDeviceModel) throws NexusException; } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/PrimaryDataDevice.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/PrimaryDataDevice.java new file mode 100644 index 00000000..f874479f --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/PrimaryDataDevice.java @@ -0,0 +1,31 @@ +package org.eclipse.dawnsci.nexus.builder.data; + +import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; + +/** + * Represents the primary data device to add to an {@link NexusDataBuilder} in order to + * build an {@link NXdata} group. This primary device is the one that contains the + * @signal field. + * + * @param the sub-interface of {@link NXobject} that the nexus object was created from + * + * @author Matthew Dickie + */ +public interface PrimaryDataDevice extends DataDevice { + + public String getSignalFieldSourceName(); + + /** + * Overrides the {@link DataDevice#isPrimary()} to return true always, as this + * is a primary device. + * + * @see org.eclipse.dawnsci.nexus.builder.data.DataDevice#isPrimary() + * @return true, always + */ + public default boolean isPrimary() { + // returns true always, do not + return true; + }; + +} \ No newline at end of file diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/AbstractNexusDataBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AbstractNexusDataBuilder.java similarity index 50% rename from org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/AbstractNexusDataBuilder.java rename to org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AbstractNexusDataBuilder.java index b8b6385d..cdf6a467 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/AbstractNexusDataBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AbstractNexusDataBuilder.java @@ -1,11 +1,13 @@ -package org.eclipse.dawnsci.nexus.builder.impl; +package org.eclipse.dawnsci.nexus.builder.data.impl; import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NexusException; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.DataDeviceBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusEntryBuilder; public abstract class AbstractNexusDataBuilder implements NexusDataBuilder { @@ -33,20 +35,21 @@ public NXdata getNxData() { return nxData; } + /* (non-Javadoc) + * @see org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder#setPrimaryDevice(org.eclipse.dawnsci.nexus.builder.NexusObjectProvider) + */ @Override - public void setPrimaryDevice(NexusObjectProvider primaryDevice) + public void setPrimaryDevice(NexusObjectProvider primaryDevice) throws NexusException { - setPrimaryDevice(new DataDevice<>(primaryDevice, false)); - } - - @Override - public void addDataDevice(NexusObjectProvider dataDevice) throws NexusException { - addDataDevice(new DataDevice<>(dataDevice, true)); + setPrimaryDevice(DataDeviceBuilder.newPrimaryDataDevice(primaryDevice)); } + /* (non-Javadoc) + * @see org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder#addDataDevice(org.eclipse.dawnsci.nexus.builder.NexusObjectProvider) + */ @Override - public void addDataDevice(NexusObjectProvider dataDevice, int defaultAxisDimension) throws NexusException { - addDataDevice(dataDevice, defaultAxisDimension, null); + public void addAxisDevice(NexusObjectProvider dataDevice) throws NexusException { + addAxisDevice(DataDeviceBuilder.newAxisDataDevice(dataDevice)); } } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisDataDeviceImpl.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisDataDeviceImpl.java new file mode 100644 index 00000000..bc3bc29e --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisDataDeviceImpl.java @@ -0,0 +1,12 @@ +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import org.eclipse.dawnsci.nexus.NXobject; +import org.eclipse.dawnsci.nexus.builder.data.AxisDataDevice; + +public class AxisDataDeviceImpl extends DataDeviceImpl implements AxisDataDevice { + + public AxisDataDeviceImpl(N nexusObject) { + super(nexusObject); + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DataFieldDimensionModel.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisFieldModel.java similarity index 73% rename from org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DataFieldDimensionModel.java rename to org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisFieldModel.java index c7aada81..a7ee3f64 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DataFieldDimensionModel.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/AxisFieldModel.java @@ -1,4 +1,6 @@ -package org.eclipse.dawnsci.nexus.builder.impl; +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import java.util.Arrays; import org.eclipse.dawnsci.nexus.NXdata; @@ -6,29 +8,16 @@ * A model for how the dimensions of a data field correspond to the dimensions * of the primary data field (i.e. the @signal field ) of an {@link NXdata} group. */ -public class DataFieldDimensionModel { +public class AxisFieldModel extends DataFieldModel { private Integer defaultAxisDimension = null; private int[] dimensionMappings = null; - public DataFieldDimensionModel() { - // do nothing - } - - public DataFieldDimensionModel(int defaultAxisDimension) { - this.defaultAxisDimension = defaultAxisDimension; + public AxisFieldModel(String sourceFieldName, int fieldRank) { + super(sourceFieldName, fieldRank); } - public DataFieldDimensionModel(Integer defaultAxisDimension, int[] dimensionMappings) { - this.defaultAxisDimension = defaultAxisDimension; - this.dimensionMappings = dimensionMappings; - } - - public Integer getDefaultAxisDimension() { - return defaultAxisDimension; - } - /** * Sets the default axis dimension for this data field to the given value. * This is the dimension of the default data field of the {@link NXdata} group @@ -39,8 +28,8 @@ public void setDefaultAxisDimension(Integer defaultAxisDimension) { this.defaultAxisDimension = defaultAxisDimension; } - public int[] getDimensionMappings() { - return dimensionMappings; + public Integer getDefaultAxisDimension() { + return defaultAxisDimension; } /** @@ -52,5 +41,16 @@ public int[] getDimensionMappings() { public void setDimensionMappings(int... dimensionMappings) { this.dimensionMappings = dimensionMappings; } + + public int[] getDimensionMappings() { + return dimensionMappings; + } + + @Override + protected void appendMemberFields(StringBuilder sb) { + super.appendMemberFields(sb); + sb.append(", defaultAxisDimension = " + defaultAxisDimension); + sb.append(", dimensionMappings = " + Arrays.toString(dimensionMappings)); + } } \ No newline at end of file diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataDeviceImpl.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataDeviceImpl.java new file mode 100644 index 00000000..9737ea21 --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataDeviceImpl.java @@ -0,0 +1,107 @@ +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.dawnsci.analysis.api.tree.Node; +import org.eclipse.dawnsci.nexus.NXdata; +import org.eclipse.dawnsci.nexus.NXobject; +import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.DataDevice; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; + +/** + * A object of this class wraps an {@link NexusObjectProvider} and contains + * additional information that can be used by a {@link NexusDataBuilder} + * describing how to add the fields for this device to an {@link NXdata} + * group when its added, either as a primary data device (by calling + * {@link NexusDataBuilder#setPrimaryDevice(org.eclipse.dawnsci.nexus.builder.data.PrimaryDataDevice)}) + * or as an axis device (by calling {@link NexusDataBuilder#addAxisDevice(org.eclipse.dawnsci.nexus.builder.data.AxisDataDevice)} + * + * @author Matthew Dickie + * @param subinterface of {@link NXobject} created by the + * wrapped {@link NexusObjectProvider} + */ +public abstract class DataDeviceImpl implements DataDevice { + + private final Map axisFields; + + private final N nexusObject; + + public DataDeviceImpl(N nexusObject) { + this.nexusObject = nexusObject; + this.axisFields = new LinkedHashMap<>(); + } + + public void addAxisField(AxisFieldModel axisFieldModel) { + axisFields.put(axisFieldModel.getSourceFieldName(), axisFieldModel); + } + + private AxisFieldModel getAxisDataFieldModel(String sourceFieldName) { + AxisFieldModel axisDataFieldModel = axisFields.get(sourceFieldName); + if (axisDataFieldModel == null) { + throw new IllegalArgumentException("No such axis field: " + sourceFieldName); + } + + return axisDataFieldModel; + } + + @Override + public final N getNexusObject() { + return nexusObject; + } + + public List getAxisFieldNames() { + return new ArrayList<>(axisFields.keySet()); + } + + public int[] getDimensionMappings(String sourceFieldName) { + return getAxisDataFieldModel(sourceFieldName).getDimensionMappings(); + } + + public Integer getDefaultAxisDimension(String sourceFieldName) { + return getAxisDataFieldModel(sourceFieldName).getDefaultAxisDimension(); + } + + public String getDestinationFieldName(String sourceFieldName) { + return getAxisDataFieldModel(sourceFieldName).getDestinationFieldName(); + } + + @Override + public Node getFieldNode(String sourceFieldName) { + return nexusObject.getNode(sourceFieldName); + } + + @Override + public int getFieldRank(String sourceFieldName) { + return getAxisDataFieldModel(sourceFieldName).getFieldRank(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("nexusObject=" + nexusObject); + appendFields(sb); + sb.append("]"); + + return sb.toString(); + } + + protected void appendFields(StringBuilder sb) { + sb.append(", axisFields={"); + sb.append("\n"); + for (Map.Entry entry : axisFields.entrySet()) { + sb.append(" "); + sb.append(entry.getKey()); + sb.append(": "); + sb.append(entry.getValue()); + sb.append("\n"); + } + sb.append("}"); + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataFieldModel.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataFieldModel.java new file mode 100644 index 00000000..2452dce7 --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DataFieldModel.java @@ -0,0 +1,71 @@ +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import java.text.MessageFormat; +import java.util.Objects; + +import org.eclipse.dawnsci.nexus.NXdata; + +/** + * A model of how a field in a nexus object should be mapped when it is added + * (i.e. linked to) in an {@link NXdata} group. + * {@link AxisFieldModel} extends this class for axis fields (which include all + * fields except the signal field). + */ +public class DataFieldModel { + + private final String sourceFieldName; + + private final int fieldRank; + + private String destinationFieldName; + + public DataFieldModel(String sourceFieldName, int fieldRank) { + this(sourceFieldName, sourceFieldName, fieldRank); + } + + public DataFieldModel(String sourceFieldName, String destinationFieldName, int fieldRank) { + Objects.requireNonNull(sourceFieldName); + Objects.requireNonNull(destinationFieldName); + if (fieldRank < 1) { + throw new IllegalArgumentException(MessageFormat.format( + "Dataset rank must be at least 1, was {0}: {1}", fieldRank, sourceFieldName)); + } + this.sourceFieldName = sourceFieldName; + this.destinationFieldName = destinationFieldName; + this.fieldRank = fieldRank; + } + + public String getDestinationFieldName() { + return destinationFieldName; + } + + public void setDestinationFieldName(String destinationFieldName) { + this.destinationFieldName = destinationFieldName; + } + + public String getSourceFieldName() { + return sourceFieldName; + } + + public int getFieldRank() { + return fieldRank; + } + + protected void appendMemberFields(StringBuilder sb) { + sb.append(getClass().getSimpleName()); + sb.append("sourceFieldName=" + sourceFieldName); + sb.append(", fieldRank=" + fieldRank); + sb.append(", destinationFieldName=" + destinationFieldName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(" ["); + appendMemberFields(sb); + sb.append("]"); + + return sb.toString(); + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilder.java similarity index 64% rename from org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilder.java rename to org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilder.java index 51c1654f..2785642a 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusDataBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/DefaultNexusDataBuilder.java @@ -10,7 +10,7 @@ * Matthew Dickie - initial API and implementation and/or initial documentation *******************************************************************************/ -package org.eclipse.dawnsci.nexus.builder.impl; +package org.eclipse.dawnsci.nexus.builder.data.impl; import java.text.MessageFormat; import java.util.Iterator; @@ -29,10 +29,14 @@ import org.eclipse.dawnsci.nexus.NXentry; import org.eclipse.dawnsci.nexus.NXobject; import org.eclipse.dawnsci.nexus.NexusException; -import org.eclipse.dawnsci.nexus.builder.DataDevice; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.impl.DefaultNexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; +import org.eclipse.dawnsci.nexus.builder.data.AxisDataDevice; +import org.eclipse.dawnsci.nexus.builder.data.DataDevice; +import org.eclipse.dawnsci.nexus.builder.data.DataDeviceBuilder; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.PrimaryDataDevice; /** * Default implementation of {@link NexusDataBuilder}. @@ -46,7 +50,9 @@ public class DefaultNexusDataBuilder extends AbstractNexusDataBuilder implements private StringDataset dimensionDefaultAxisNames; - private String signalFieldName; + private String signalFieldSourceName; + + private String signalFieldDestName; /** * Create a new {@link DefaultNexusDataBuilder}. This constructor should only be @@ -54,8 +60,7 @@ public class DefaultNexusDataBuilder extends AbstractNexusDataBuilder implements * @param entryBuilder parent entry builder * @param nxData {@link NXdata} object to wrap */ - protected DefaultNexusDataBuilder(NexusEntryBuilder entryBuilder, - final NXdata nxData) { + public DefaultNexusDataBuilder(NexusEntryBuilder entryBuilder, final NXdata nxData) { super(entryBuilder, nxData); } @@ -72,83 +77,40 @@ private boolean isPrimaryDeviceAdded() { } /* (non-Javadoc) - * @see org.eclipse.dawnsci.nexus.builder.NexusDataBuilder#setPrimaryDevice(org.eclipse.dawnsci.nexus.builder.DataDevice) + * @see org.eclipse.dawnsci.nexus.builder.NexusDataBuilder#setPrimaryDevice(org.eclipse.dawnsci.nexus.builder.DataDevice.PrimaryDataDevice) */ @Override - public void setPrimaryDevice(DataDevice primaryDeviceModel) + public void setPrimaryDevice(PrimaryDataDevice primaryDataDevice) throws NexusException { - NexusObjectProvider nexusObjectProvider = primaryDeviceModel.getNexusObjectProvider(); - String signalSourceFieldName = primaryDeviceModel.getSignalDataSourceFieldName(); - String signalDestFieldName = primaryDeviceModel.getDestinationFieldName(signalSourceFieldName); - addSignalAndAxesAttributes(nexusObjectProvider, signalSourceFieldName, signalDestFieldName); + addSignalAndAxesAttributes(primaryDataDevice); - addDevice(primaryDeviceModel, true); + addDevice(primaryDataDevice, true); } /* (non-Javadoc) * @see org.eclipse.dawnsci.nexus.builder.NexusDataBuilder#addDataDevice(org.eclipse.dawnsci.nexus.builder.NexusObjectProvider, java.lang.Integer, int[]) */ @Override - public void addDataDevice(NexusObjectProvider dataDevice, + public void addAxisDevice(NexusObjectProvider dataDevice, Integer defaultAxisDimension, int... dimensionMappings) throws NexusException { - addDataDevice(new DataDevice<>(dataDevice, true, defaultAxisDimension, dimensionMappings)); + DataDeviceBuilder builder = DataDeviceBuilder.newAxisDataDeviceBuilder(dataDevice, defaultAxisDimension); + builder.setDefaultDimensionMappings(dimensionMappings); + + addAxisDevice((AxisDataDevice) builder.build()); } /* (non-Javadoc) - * @see org.eclipse.dawnsci.nexus.builder.NexusDataBuilder#addDataDevice(org.eclipse.dawnsci.nexus.builder.DataDevice) + * @see org.eclipse.dawnsci.nexus.builder.NexusDataBuilder#addDataDevice(org.eclipse.dawnsci.nexus.builder.DataDevice.AxisDataDevice) */ @Override - public void addDataDevice(DataDevice dataDevice) throws NexusException { + public void addAxisDevice(AxisDataDevice axisDataDevice) throws NexusException { if (!isPrimaryDeviceAdded()) { throw new IllegalStateException("The primary device has not been set."); } - addDevice(dataDevice, false); + addDevice(axisDataDevice, false); } - /** - * Returns the node for the field with the given name within the nexus object for the given - * {@link NexusObjectProvider}. The node may be a {@link DataNode} or a {@link SymbolicNode}. - * @param nexusObjectProvider nexus object provider - * @param fieldName field name - * @return node within the {@link NexusObjectProvider} with the given name - * @throws NexusException if the nexus object could not be created for any reason - */ - private Node getFieldNode(NexusObjectProvider nexusObjectProvider, - String fieldName) throws NexusException { - final NXobject nexusObject = nexusObjectProvider.getNexusObject(entryBuilder.getNodeFactory(), true); - final Node childNode = nexusObject.getNode(fieldName); - if (childNode == null || childNode.isGroupNode()) { - throw new IllegalArgumentException(MessageFormat.format( - "The {0} does not have a data node or symbolic node with the name: {1}", - nexusObject.getNXclass().getSimpleName(), fieldName)); - } - - return childNode; - } - - private int getFieldRank(NexusObjectProvider nexusObjectProvider, - String fieldName) throws NexusException { - final NXobject nexusObject = nexusObjectProvider.getNexusObject(entryBuilder.getNodeFactory(), true); - final Node childNode = nexusObject.getNode(fieldName); - if (childNode == null || childNode.isGroupNode()) { - throw new IllegalArgumentException(MessageFormat.format( - "The {0} does not have a data node or symbolic node with the name: {1}", - nexusObject.getNXclass().getSimpleName(), fieldName)); - } - - if (childNode.isSymbolicNode()) { - try { - return nexusObjectProvider.getExternalDatasetRank(fieldName); - } catch (IllegalArgumentException e) { - throw new NexusException(MessageFormat.format( - "The rank of the external dataset ''{0}'' must be specified.", fieldName)); - } - } - - return ((DataNode) childNode).getRank(); - } - /** * Adds the data fields for the given device to the {@link NXdata} * @param dataDevice data device, wrapping an {@link NexusObjectProvider} @@ -156,24 +118,16 @@ private int getFieldRank(NexusObjectProvider nexusObjectProv * @throws NexusException */ private void addDevice(DataDevice dataDevice, boolean isPrimary) throws NexusException { - NexusObjectProvider nexusObjectProvider = dataDevice.getNexusObjectProvider(); - String targetPrefix = getPath(nexusObjectProvider.getNexusObject()); + String targetPrefix = getPath(dataDevice.getNexusObject()); + + // if this is the primary device, add the signal field + if (isPrimary) { + addDataField(dataDevice, signalFieldSourceName, targetPrefix); + } - for (String sourceFieldName : dataDevice.getSourceFieldNames()) { - String destinationFieldName = dataDevice.getDestinationFieldName(sourceFieldName); - int[] dimensionMappings = dataDevice.getDimensionMappings(sourceFieldName); - Integer defaultAxisDimension = dataDevice.getDefaultAxisDimension(sourceFieldName); - - if (isPrimary) { - // the primary device (i.e. a detector) may know its own dimension mappings for some fields - // as it is the owner of the default dataset of the NXdata group - if (defaultAxisDimension == null) { - defaultAxisDimension = nexusObjectProvider.getDefaultAxisDimension(signalFieldName, sourceFieldName); - } - dimensionMappings = nexusObjectProvider.getDimensionMappings(signalFieldName, sourceFieldName); - } - addDataField(nexusObjectProvider, sourceFieldName, destinationFieldName, - defaultAxisDimension, dimensionMappings, targetPrefix); + // add the axis fields for this device + for (String sourceFieldName : dataDevice.getAxisFieldNames()) { + addDataField(dataDevice, sourceFieldName, targetPrefix); } } @@ -237,25 +191,19 @@ private void addDeviceToDefaultAxes(int defaultAxisDimension, String destination * * @param nexusObjectProvider nexus object provider to get the nexus object from * @param sourceFieldName name of field within the nexus object - * @param destinationFieldName name of new link for field from the NXdata group - * @param defaultAxisDimension default axis dimensions for field, or null - * for none - * @param dimensionMappings dimension mappings for field, or null for default * @param targetPrefix prefix of @target attribute * @throws NexusException */ - private void addDataField(NexusObjectProvider nexusObjectProvider, - String sourceFieldName, String destinationFieldName, Integer defaultAxisDimension, - int[] dimensionMappings, String targetPrefix) throws NexusException { - // get the node for the given field (a DataNode or SymbolicNode, exception if doesn't exist) - final Node fieldNode = getFieldNode(nexusObjectProvider, sourceFieldName); - final int fieldRank = getFieldRank(nexusObjectProvider, sourceFieldName); - + private void addDataField(DataDevice dataDevice, + String sourceFieldName, String targetPrefix) throws NexusException { + String destinationFieldName = dataDevice.getDestinationFieldName(sourceFieldName); // check that there is not an existing node with the same name if (nxData.containsDataNode(destinationFieldName)) { throw new IllegalArgumentException("The NXdata element already contains a data node with the name: " + destinationFieldName); } + // add the node to the nxData group + final Node fieldNode = dataDevice.getFieldNode(sourceFieldName); addFieldNode(destinationFieldName, fieldNode); // create the @target attribute if not already present @@ -268,18 +216,18 @@ private void addDataField(NexusObjectProvider nexusObjec // dataNode.addAttribute(TreeFactory.createAttribute(ATTR_NAME_LONG_NAME, sourceFieldName)); // } - // create the @axis indices attribute - if (!destinationFieldName.equals(signalFieldName)) { - final Attribute axisIndicesAttribute = createAxisIndicesAttribute( - sourceFieldName, destinationFieldName, defaultAxisDimension, - dimensionMappings, fieldNode, fieldRank); + // create the @{axisname}_indices attribute + if (!destinationFieldName.equals(signalFieldDestName)) { + final Attribute axisIndicesAttribute = createAxisIndicesAttribute(dataDevice, sourceFieldName); nxData.addAttribute(axisIndicesAttribute); + + // add the axis dimension to the default axes - the @axes attribute + Integer defaultAxisDimension = dataDevice.getDefaultAxisDimension(sourceFieldName); + if (defaultAxisDimension != null) { + addDeviceToDefaultAxes(defaultAxisDimension, destinationFieldName); + } } - // add the axis dimension to the default axes - the @axes attribute - if (defaultAxisDimension != null) { - addDeviceToDefaultAxes(defaultAxisDimension, destinationFieldName); - } } private void addFieldNode(String destinationFieldName, Node node) { @@ -300,26 +248,27 @@ private void addFieldNode(String destinationFieldName, Node node) { /** * Adds the @signal and @axes attributes to the {@link NXdata} group. - * @param nexusObjectProvider + * @param primaryDataDevice * @param sourceFieldName * @param destinationFieldName * @throws NexusException */ - private void addSignalAndAxesAttributes( - NexusObjectProvider nexusObjectProvider, - String sourceFieldName, String destinationFieldName) throws NexusException { + private void addSignalAndAxesAttributes(PrimaryDataDevice primaryDataDevice) throws NexusException { if (isPrimaryDeviceAdded()) { throw new IllegalArgumentException("Primary device already added"); } + + // get the source and destination name for the signal field + signalFieldSourceName = primaryDataDevice.getSignalFieldSourceName(); + signalFieldDestName = primaryDataDevice.getDestinationFieldName(signalFieldSourceName); - signalFieldName = destinationFieldName; - final Attribute signalAttribute = TreeFactory.createAttribute(ATTR_NAME_SIGNAL, signalFieldName, false); + final Attribute signalAttribute = TreeFactory.createAttribute(ATTR_NAME_SIGNAL, signalFieldDestName, false); nxData.addAttribute(signalAttribute); // create the 'axes' attribute of the NXgroup and set each axis name // to the placeholder value "." - signalNode = getFieldNode(nexusObjectProvider, sourceFieldName); - signalFieldRank = getFieldRank(nexusObjectProvider, sourceFieldName); + signalNode = primaryDataDevice.getFieldNode(signalFieldSourceName); + signalFieldRank = primaryDataDevice.getFieldRank(signalFieldSourceName); dimensionDefaultAxisNames = new StringDataset(signalFieldRank); dimensionDefaultAxisNames.fill(NO_DEFAULT_AXIS_PLACEHOLDER); @@ -327,11 +276,14 @@ private void addSignalAndAxesAttributes( nxData.addAttribute(axesAttribute); } - private Attribute createAxisIndicesAttribute(String sourceFieldName, - String destinationFieldName, Integer defaultAxisDimension, - int[] dimensionMappings, Node dataNode, int fieldRank) { + private Attribute createAxisIndicesAttribute(DataDevice dataDevice, String sourceFieldName) { // if the default axis dimension is specified and the dataset has a rank of 1, // then this has to be the dimension mapping as well + final String destinationFieldName = dataDevice.getDestinationFieldName(sourceFieldName); + final int fieldRank = dataDevice.getFieldRank(sourceFieldName); + final Integer defaultAxisDimension = dataDevice.getDefaultAxisDimension(sourceFieldName); + int[] dimensionMappings = dataDevice.getDimensionMappings(sourceFieldName); + if (defaultAxisDimension != null && fieldRank == 1) { dimensionMappings = new int[] { defaultAxisDimension }; } diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataDeviceImpl.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataDeviceImpl.java new file mode 100644 index 00000000..ef536119 --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataDeviceImpl.java @@ -0,0 +1,49 @@ +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import org.eclipse.dawnsci.nexus.NXobject; +import org.eclipse.dawnsci.nexus.builder.data.PrimaryDataDevice; + +public class PrimaryDataDeviceImpl extends DataDeviceImpl implements PrimaryDataDevice { + + private final String signalFieldSourceName; + + private final DataFieldModel signalFieldModel; + + public PrimaryDataDeviceImpl(N nexusObject, DataFieldModel signalFieldModel) { + super(nexusObject); + this.signalFieldSourceName = signalFieldModel.getSourceFieldName(); + this.signalFieldModel = signalFieldModel; + } + + @Override + public String getSignalFieldSourceName() { + return signalFieldModel.getSourceFieldName(); + } + + @Override + public int getFieldRank(String sourceFieldName) { + if (sourceFieldName.equals(signalFieldSourceName)) { + return signalFieldModel.getFieldRank(); + } + + return super.getFieldRank(sourceFieldName); + } + + @Override + public String getDestinationFieldName(String sourceFieldName) { + if (sourceFieldName.equals(signalFieldSourceName)) { + return signalFieldModel.getDestinationFieldName(); + } + + return super.getDestinationFieldName(sourceFieldName); + } + + protected void appendFields(StringBuilder sb) { + sb.append(", signalField="); + sb.append(signalFieldModel); + sb.append("\n"); + + super.appendFields(sb); + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataFieldModel.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataFieldModel.java new file mode 100644 index 00000000..24d2ca3c --- /dev/null +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/data/impl/PrimaryDataFieldModel.java @@ -0,0 +1,64 @@ +package org.eclipse.dawnsci.nexus.builder.data.impl; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Models the mappings for a primary data field from the other data fields within the same device. + * @author Matthew Dickie + */ +public class PrimaryDataFieldModel { + + private static final class AxisFieldDimensionModel { + + private final Integer defaultAxisDimension; + private final int[] dimensionMappings; + + AxisFieldDimensionModel(Integer defaultAxisDimension, int[] dimensionMappings) { + this.defaultAxisDimension = defaultAxisDimension; + this.dimensionMappings = dimensionMappings; + } + + public Integer getDefaultAxisDimension() { + return defaultAxisDimension; + } + + public int[] getDimensionMappings() { + return dimensionMappings; + } + + } + + private final Map axisFieldDimensionModels = new LinkedHashMap<>(); + + public void addAxisField(String axisFieldName, Integer defaultAxisDimension, + int[] dimensionMappings) { + axisFieldDimensionModels.put(axisFieldName, + new AxisFieldDimensionModel(defaultAxisDimension, dimensionMappings)); + } + + public List getAxisFieldNames() { + return new ArrayList<>(axisFieldDimensionModels.keySet()); + } + + public Integer getDefaultAxisDimension(String dataFieldName) { + AxisFieldDimensionModel axisFieldDimensionModel = axisFieldDimensionModels.get(dataFieldName); + if (axisFieldDimensionModel != null) { + return axisFieldDimensionModel.getDefaultAxisDimension(); + } + + return null; + } + + public int[] getDimensionMappings(String dataFieldName) { + AxisFieldDimensionModel axisFieldDimensionModel = axisFieldDimensionModels.get(dataFieldName); + if (axisFieldDimensionModel != null) { + return axisFieldDimensionModel.getDimensionMappings(); + } + + return null; + } + +} diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilder.java index 674fb3b2..0942b609 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusEntryBuilder.java @@ -30,7 +30,6 @@ import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; import org.eclipse.dawnsci.nexus.builder.CustomNexusEntryModification; -import org.eclipse.dawnsci.nexus.builder.NexusDataBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryModification; import org.eclipse.dawnsci.nexus.builder.NexusMetadataProvider; @@ -38,6 +37,8 @@ import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.appdef.NexusApplicationBuilder; import org.eclipse.dawnsci.nexus.builder.appdef.impl.DefaultApplicationFactory; +import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; +import org.eclipse.dawnsci.nexus.builder.data.impl.DefaultNexusDataBuilder; import org.eclipse.dawnsci.nexus.validation.NexusValidationException; /** diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusFileBuilder.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusFileBuilder.java index 5429a4be..97affd3c 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusFileBuilder.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/DefaultNexusFileBuilder.java @@ -84,7 +84,7 @@ public NXroot getNXroot() { * @see org.eclipse.dawnsci.nexus.builder.NexusFileBuilder#newEntry() */ @Override - public NexusEntryBuilder newEntry() throws NexusException { + public DefaultNexusEntryBuilder newEntry() throws NexusException { return newEntry("entry"); } @@ -92,7 +92,7 @@ public NexusEntryBuilder newEntry() throws NexusException { * @see org.eclipse.dawnsci.nexus.builder.NexusFileBuilder#newEntry(java.lang.String) */ @Override - public NexusEntryBuilder newEntry(String entryName) throws NexusException { + public DefaultNexusEntryBuilder newEntry(String entryName) throws NexusException { if (entries.containsKey(entryName)) { throw new NexusException("An entry with the name " + entryName + " already exists"); } @@ -100,7 +100,7 @@ public NexusEntryBuilder newEntry(String entryName) throws NexusException { final NXentry entry = nexusNodeFactory.createNXentry(); nxRoot.setEntry(entryName, entry); - NexusEntryBuilder entryModel = new DefaultNexusEntryBuilder(nexusNodeFactory, entryName, entry); + DefaultNexusEntryBuilder entryModel = new DefaultNexusEntryBuilder(nexusNodeFactory, entryName, entry); entries.put(entryName, entryModel); return entryModel; diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/NexusUser.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/NexusUser.java index 00d5e1a7..68e9ac90 100644 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/NexusUser.java +++ b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/NexusUser.java @@ -3,7 +3,7 @@ import org.eclipse.dawnsci.nexus.NXuser; import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusNodeFactory; -import org.eclipse.dawnsci.nexus.builder.AbstractNexusProvider; +import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; /** @@ -11,7 +11,7 @@ * a {@link NexusEntryBuilder} using the {@link NexusEntryBuilder#add(org.eclipse.dawnsci.nexus.builder.NexusObjectProvider) * method to add a user to the nexus entry. */ -public class NexusUser extends AbstractNexusProvider { +public class NexusUser extends AbstractNexusObjectProvider { private static final String FIELD_NAME_USERNAME = "username"; diff --git a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/PrimaryDataFieldModel.java b/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/PrimaryDataFieldModel.java deleted file mode 100644 index 7d647cc4..00000000 --- a/org.eclipse.dawnsci.nexus/src/org/eclipse/dawnsci/nexus/builder/impl/PrimaryDataFieldModel.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.eclipse.dawnsci.nexus.builder.impl; - -import java.util.HashMap; -import java.util.Map; - -/** - * Models the mappings for a primary data field from the other data fields within the same device. - * @author Matthew Dickie - */ -public class PrimaryDataFieldModel { - - private Map dataFieldDimensionModels = new HashMap<>(4); - - public PrimaryDataFieldModel() { - // nothing to do - } - - public void addDataField(String dataFieldName, Integer defaultAxisDimension) { - DataFieldDimensionModel fieldDimModel = new DataFieldDimensionModel(defaultAxisDimension); - dataFieldDimensionModels.put(dataFieldName, fieldDimModel); - } - - public void addDataField(String dataFieldName, Integer defaultAxisDimension, int[] dimensionMappings) { - DataFieldDimensionModel fieldDimModel = new DataFieldDimensionModel(defaultAxisDimension, - dimensionMappings); - dataFieldDimensionModels.put(dataFieldName, fieldDimModel); - } - - public Integer getDefaultAxisDimension(String dataFieldName) { - DataFieldDimensionModel fieldDimModel = dataFieldDimensionModels.get(dataFieldName); - if (fieldDimModel != null) { - return fieldDimModel.getDefaultAxisDimension(); - } - - return null; - } - - public int[] getDimensionMappings(String dataFieldName) { - DataFieldDimensionModel fieldDimModel = dataFieldDimensionModels.get(dataFieldName); - if (fieldDimModel != null) { - return fieldDimModel.getDimensionMappings(); - } - - return null; - } - -}