A client uses the NetcdfFile, NetcdfDataset, or one of the Scientific Feature Type APIs to read data from a CDM file. These provide a rich and sometimes complicated API to the client. Behind the scenes, when any of these APIs actually read from a dataset, however, they use a very much simpler interface, the I/O Service Provider or IOSP for short. The Netcdf Java library has many implementations of this interface, one for each different file format that it knows how to read. This design pattern is called a Service Provider.
IOSPs are managed by the NetcdfFile class. When a client requests a dataset (by calling NetcdfFile.open), the file is opened as a ucar.unidata.io.RandomAccessFile (an improved version of java.io.RandomAccessFile). Each registered IOSP is then asked "is this your file?" by calling isValidFile( ucar.unidata.io.RandomAccessFile). The first one that returns true claims it. When you implement isValidFile() in your IOSP, it must be very fast and accurate.
public interface ucar.nc2.IOServiceProvider { // Check if this is a valid file for this IOServiceProvider // Required if you are registering your IOSP with NetcdfFile.registerIOProvider() public boolean isValidFile( ucar.unidata.io.RandomAccessFile raf) throws IOException; // Open existing file, and populate ncfile with it. public void open(ucar.unidata.io.RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask) throws IOException; // Read data from a top level Variable and return a memory resident Array. public ucar.ma2.Array readData(ucar.nc2.Variable v2, Section section) throws java.io.IOException, ucar.ma2.InvalidRangeException; // Close the file. public void close() throws IOException; // Get the file type id. public String getFileTypeId(); // Get the version of the file type. public String getFileTypeVersion(); // Get a human-readable description for this file type. public String getFileTypeDescription(); ///////////////////////////////////// // optional // must implement if you have top level sequences 6) public StructureDataIterator getStructureIterator(Structure s, int bufferSize) throws java.io.IOException; // Read sections of nested variables nested inside a Structure 7) public ucar.ma2.Array readSection(ParsedSectionSpec cer) throws IOException, InvalidRangeException; // Read data from a top level Variable and send data to a WritableByteChannel. 8) public long readToByteChannel(ucar.nc2.Variable v2, Section section, WritableByteChannel channel) throws java.io.IOException, ucar.ma2.InvalidRangeException; // Extend the file if needed in a way that is compatible with the current metadata. 9) public boolean syncExtend() throws IOException; // Check if file has changed, and reread metadata if needed. 10) public boolean sync() throws IOException; // A way to communicate arbitrary information to an iosp. 11) public Object sendIospMessage( Object message); // print Debug info for this object. 12) public String toStringDebug(Object o); // Show debug / underlying implementation details 13) public String getDetailInfo(); }
Your implementataion class should extend ucar.nc2.iosp.AbstractIOServiceProvider. This provides default implementation of some of the methods, so minimally, you only have to implement 4 methods:
public class MyIosp extends ucar.nc2.iosp.AbstractIOServiceProvider { 1) public boolean isValidFile(RandomAccessFile raf) throws IOException {} 2) public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask) throws IOException {} 3) public Array readData(Variable v2, Section wantSection) throws IOException, InvalidRangeException {} 4) public void close() throws IOException {} 5) public String getFileTypeId() {} 5) public String getFileTypeVersion() {} 5) public String getFileTypeDescription(); }