/*
 * Copyright 1998, University Corporation for Atmospheric Research
 * All Rights Reserved.
 * See file LICENSE for copying and redistribution conditions.
 *
 * $Id: Plain.java,v 1.28 2002-10-21 20:07:44 donm Exp $
 */

package visad.data.netcdf;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import ucar.netcdf.Netcdf;
import ucar.netcdf.NetcdfFile;
import ucar.netcdf.Schema;
import ucar.netcdf.Variable;
import ucar.netcdf.VariableIterator;
import visad.data.BadFormException;
import visad.data.FormNode;
import visad.data.netcdf.in.*;
import visad.data.netcdf.out.VisADAdapter;
import visad.Data;
import visad.DataImpl;
import visad.UnimplementedException;
import visad.VisADException;


/**
 * A moderately stupid implementation of a netCDF data form for the
 * storage of persistent data objects on local disk.
 */
public class
Plain
    extends NetCDF
{
    /**
     * The quantity database to use for mapping netCDF variables to
     * VisAD Quantity-s.
     */
    private final QuantityDB    quantityDB;

    /**
     * The flag for transforming netCDF char variables to Text
     */
    private final boolean    charToText;


    /**
     * Constructs a default, netCDF data form.
     *
     * @throws VisADException   Couldn't create necessary VisAD object
     */
    public
    Plain()
        throws VisADException
    {
        this(QuantityDBManager.instance(), false);
    }

    /**
     * Constructs a netCDF data form that converts
     *
     * @param charToText                The char to Text flag
     */
    public
    Plain(boolean charToText)
    {
        this(QuantityDBManager.instance(), charToText);
    }

    /**
     * Constructs a netCDF data form that uses the given quantity database.
     *
     * @param db                        The quantity database.
     */
    public
    Plain(QuantityDB db)
    {
        this(db, false);
    }

    /**
     * Constructs a netCDF data form that uses the given quantity database,
     * and the flag for converting char to Text.
     *
     * @param db                        The quantity database.
     * @param charToText                The char to Text flag
     */
    public
    Plain(QuantityDB db, boolean charToText)
    {
        super("Plain");
        quantityDB = db;
        this.charToText = charToText;
    }


    /**
     * Save a VisAD data object in this form.
     *
     * @param path                      The pathname of the netCDF file to
     *                                  be created.
     * @param data                      The data to be saved.
     * @param replace                   Whether to replace an existing file.
     * @exception BadFormException      netCDF can't handle data object
     * @exception VisADException        Couldn't create necessary VisAD object
     * @exception IOException           I/O error.  File might already exist.
     * @exception RemoteException       Remote execution error
     * @exception UnimplementedException
     *                                  Not yet!
     */
    public synchronized void
    save(String path, Data data, boolean replace)
        throws BadFormException, IOException, RemoteException, VisADException,
            UnimplementedException
    {
        VisADAdapter    adapter = new VisADAdapter(data);
        Schema          schema = new Schema(adapter);
        NetcdfFile      file = new NetcdfFile(path, replace, /*fill=*/false,
                                        schema);

        try
        {
            VariableIterator    iter = file.iterator();

            while (iter.hasNext())
            {
                Variable        outVar = iter.next();
                Variable        inVar = adapter.get(outVar.getName());
                int             rank = outVar.getRank();
                int[]           origin = new int[rank];

                for (int i = 0; i < rank; ++i)
                    origin[i] = 0;

                outVar.copyin(origin, inVar);
            }
        }
        finally
        {
            file.close();
        }
    }


    /**
     * Add data to an existing data object.
     *
     * @param id        Pathname of the existing netCDF file.
     * @param data      Data to be saved.
     * @param replace   Whether or not to replace duplicate, existing data.
     * @exception BadFormException
     *                  netCDF can't handle data object.
     */
    public synchronized void
    add(String id, Data data, boolean replace)
        throws BadFormException
    {
    }


    /**
     * Returns a VisAD data object corresponding to a netCDF dataset.
     *
     * @param spec              Specification of the existing netCDF dataset.
     * @return                  A VisAD data object corresponding to the netCDF 
     *                          dataset.
     * @throws BadFormException if the netCDF dataset cannot be adapted to a
     *                          VisAD data object.
     * @throws VisADException   if a problem occurs in core VisAD.  Probably a
     *                          VisAD object couldn't be created.
     * @throws IOException      if an I/O failure occurs.
     * @see NetcdfAdapter#getData()
     */
    public synchronized DataImpl
    open(String spec)
        throws BadFormException, IOException, VisADException
    {
        return
            new NetcdfAdapter(
                new NetcdfFile(spec, /*readonly=*/true),
                quantityDB,
                charToText
            ).getData();
    }


    /**
     * Returns a VisAD data object corresponding to a netCDF dataset
     * and imported according to a given strategy.  Among the
     * pre-defined import strategies are {@link Strategy#DEFAULT},
     * {@link Strategy#MERGED_FILE_FLAT_FIELDS}, {@link
     * Strategy#UNMERGED_FILE_FLAT_FIELDS}, and {@link Strategy#IN_MEMORY}.
     *
     * @param spec              Specification of the existing netCDF dataset.
     * @param strategy          The data-import strategy.
     * @return                  A VisAD data object corresponding to the netCDF 
     *                          dataset.
     * @throws BadFormException if the netCDF dataset cannot be adapted to a
     *                          VisAD data object.
     * @throws VisADException   if a problem occurs in core VisAD.  Probably a
     *                          VisAD object couldn't be created.
     * @throws IOException      if an I/O failure occurs.
     * @see NetcdfAdapter#getData(Strategy)
     */
    public synchronized DataImpl
    open(String spec, Strategy strategy)
        throws BadFormException, IOException, VisADException
    {
        return
            new NetcdfAdapter(
                new NetcdfFile(spec, /*readonly=*/true),
                quantityDB,
                charToText
            ).getData(strategy);
    }


    /**
     * Open an existing netCDF file and return a proxy for a VisAD data object.
     *
     * @param path      Pathname of the existing netCDF file.
     * @return          A VisAD object corresponding to the netCDF dataset.
     * @exception BadFormException
     *                  The netCDF variable cannot be adapted to a VisAD API.
     * @exception VisADException
     *                  Problem in core VisAD.  Probably some VisAD object
     *                  couldn't be created.
     * @exception IOException
     *                  Data access I/O failure.
     */
    public synchronized DataImpl
    openProxy(String path)
        throws BadFormException, IOException, VisADException
    {
        NetcdfFile      file = new NetcdfFile(path, /*readonly=*/true);

        return new NetcdfAdapter(file, quantityDB, charToText).getProxy();
    }


    /**
     * Returns a VisAD data object corresponding to a URL.  If the query
     * component of the URL is null, then the returned object will
     * contain all the variables in the netCDF dataset.  If the query component
     * is non-null, then it must comprise a comma-separated list of
     * netCDF variable names; the returned VisAD data object will contain only
     * those variables in the netCDF dataset that are also named in the list
     * (i.e. the intersection is returned).  Consequently, if the list is empty,
     * then null is returned.  For example, this form:
     *  open(new URL("file://myfile.nc?var_one,var_two")); 
     * will return a VisAD data object consisting only of the
     * netCDF variables var_one and var_two
     * assuming they are in the file.
     *
     * @param url             The URL of the netCDF dataset.
     * @return                A VisAD object corresponding to the netCDF datset
     *                        or null.
     * @throws FileNotFoundException
     *                        if the URL specifies a file that doesn't exist.
     * @throws IOException    if an I/O failure occurs.
     * @throws VisADException if a necessary VisAD object couldn't be created.
     */
    public synchronized DataImpl
    open (URL url)
        throws FileNotFoundException, IOException, VisADException
    {
        /*
         * URL.getQuery() isn't used to accomodate JDK 1.2.
         */
        String query;
        {
            String file = url.getFile();
            int    i = file.indexOf('?');
            if (i == -1)
            {
                query = null;
            }
            else
            {
                query =
                    i == file.length() - 1
                        ? ""
                        : file.substring(i+1);
            }
        }
        Set    names = new TreeSet();
        if (query != null)
        {
            for (StringTokenizer st = new StringTokenizer(query, ",");
                st.hasMoreTokens(); )
            {
                names.add(st.nextToken());
            }
        }
        Netcdf netcdf = new NetcdfFile(url);
        return
            new NetcdfAdapter(
                query == null
                    ? netcdf
                    : new VariableFilter(netcdf, names),
                quantityDB, charToText).getData();
    }


    /**
     * Return the data forms that are compatible with a data object.
     *
     * @param data      The VisAD data object to be examined.
     * @return          this if data is compatible;
     *                  otherwise, null.
     * @exception VisADException        Problem with core VisAD.
     * @exception IOException           Problem with local data access.
     * @exception RemoteException       Problem with remote data access.
     */
    public synchronized FormNode
    getForms(Data data)
        throws VisADException, RemoteException, IOException
    {
        FormNode        form;

        try
        {
            VisADAdapter        adapter = new VisADAdapter(data);
            form = this;
        }
        catch (BadFormException e)
        {
            form = null;
        }

        return form;
    }


    /**
     * Test this class.
     *
     * @param args              Runtime arguments.  Ignored.
     * @exception Exception     Something went wrong.
     */
    public static void main(String[] args)
        throws Exception
    {
        String  inPath;
        String  outPath = "plain.nc";

        if (args.length == 0)
            inPath = "test.nc";
        else
            inPath = args[0];

        Plain   plain = new Plain(args.length > 1);

        System.out.println("Opening netCDF dataset \"" + inPath + "\"");

        Data    data;
        try
        {
            URL url = new URL(inPath);
            data = plain.open(url);
        }
        catch (MalformedURLException e)
        {
            data = plain.open(inPath);
        }

        if (data == null)
        {
            System.out.println("No data");
        }
        else
        {
            // System.out.println("Data:\n" + data);
            System.out.println("data.getType().toString():\n" +
                data.getType());
            System.out.println("Writing netCDF dataset \"" + outPath + "\"");
            plain.save(outPath, data, /*replace=*/true);
        }
    }
}

 

Ads help maintain this website.