// $Id: AbstractNetcdf.java,v 1.4 2002-05-29 18:31:32 steve Exp $ /* * Copyright 1997-2000 Unidata Program Center/University Corporation for * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307, * support@unidata.ucar.edu. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package ucar.netcdf; import ucar.multiarray.Accessor; import java.util.Hashtable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * This abstract class provides a skeletal implementation * of the Netcdf interface. * <p> * A minimal concrete implementation * would provide a concrete implementation of method * <code>Accessor ioFactory(ProtoVariable proto)</code>. * It would also provide a constructor which takes a Schema * argument and calls super(Schema) to get this class to * hook everything up. * <p> * TODO: There is a lot more to be said. * * @author $Author: steve $ * @version $Revision: 1.4 $ $Date: 2002-05-29 18:31:32 $ */ public abstract class AbstractNetcdf implements Netcdf { /* Begin Constructors */ /** * Create an empty instance. * This may be incrementally populated using the protected * put methods below. Use this constructor when you don't * have all the ProtoVariables, Dimensions, and global * Attributes available initially, such as when constructing * from a stream. */ protected AbstractNetcdf() { ctor = VariableCtor(); delegate = new Schema(); variables = new Hashtable(); } /** * Create an empty instance to be populated with instances * of some subclass of Variable. * * @param varClass Class object for some subclass of Variable. * The class must implement a constructor of the form * <code>myVar(ProtoVariable proto, Accessor io)</code> * or NoSuchMethodException will be thrown. */ protected AbstractNetcdf(Class varClass) throws NoSuchMethodException { ctor = varClass.getDeclaredConstructor( varCtorParameterTypes() ); delegate = new Schema(); variables = new Hashtable(); } /** * Create an instance populated with instances * of Variable. * * @param sc the Schema to use. N.B. Not a copy. * May be empty, shouldn't be null. * * @param init if true, call initHashtable() */ protected AbstractNetcdf(Schema sc, boolean init) { ctor = VariableCtor(); delegate = sc; variables = new Hashtable(delegate.size()); if(init) { try { initHashtable(); } catch (InstantiationException ie) { // Can't happen: Variable is concrete throw new Error(); } catch (IllegalAccessException iae) { // Can't happen: Variable is accessable throw new Error(); } catch (InvocationTargetException ite) { // all the possible target exceptions are // RuntimeException throw (RuntimeException) ite.getTargetException(); } } } /** * Create an instance populated with instances * of some subclass of Variable. * * @param sc the Schema used as a template. * May be empty, shouldn't be null. * * @param init if true, call initHashtable() * * @param varClass Class object for some subclass of Variable. * The class must implement a constructor of the form * <code>myVar(ProtoVariable proto, Accessor io)</code> * or NoSuchMethodException will be thrown. */ protected AbstractNetcdf(Schema sc, boolean init, Class varClass) throws NoSuchMethodException, InstantiationException, InvocationTargetException, IllegalAccessException { ctor = varClass.getDeclaredConstructor( varCtorParameterTypes() ); delegate = new Schema(sc); variables = new Hashtable(delegate.size()); if(init) initHashtable(); } /* End Constructors */ /** * Returns the number of variables * @return int number of variables */ public int size() { // assert(delegate.size() == variables.size(); return variables.size(); } /** * Returns VariableIterator for the elements. * @return VariableIterator for the elements. * @see VariableIterator */ public VariableIterator iterator() { return new VariableIterator() { final ProtoVariableIterator iter = delegate.iterator(); public boolean hasNext() { return iter.hasNext(); } public Variable next() { return (Variable) variables.get( iter.next().getName()); } }; } /** * Retrieve the variable associated with the specified name. * @param name String which identifies the desired variable * @return the variable, or null if not found */ public Variable get(String name) { return (Variable) variables.get(name); } /** * Tests if the Variable identified by <code>name</code> * is in this set. * @param name String which identifies the desired variable * @return <code>true</code> if and only if this set contains * the named variable. */ public boolean contains(String name) { /* * assert(delegate.contains(name) * == variables.containsKey(name)(); */ return variables.containsKey(name); } /** * Tests if the argument is in this set. * @param oo some Object * @return <code>true</code> if and only if this set contains * <code>oo</code> */ public boolean contains(Object oo) { return variables.contains(oo); } /** * Returns the set of dimensions associated with this, * the union of those used by each of the variables. * * @return DimensionSet containing dimensions used * by any of the variables. May be empty. Won't be null. */ public DimensionSet getDimensions() { return delegate.getDimensions(); } /** * Returns the set of attributes associated with this, * also know as the "global" attributes. * * @return AttributeSet. May be empty. Won't be null. */ public AttributeSet getAttributes() { return delegate.getAttributes(); } /** * Convenience function; look up global Attribute by name. * * @param name the name of the attribute * @return the attribute, or null if not found */ public Attribute getAttribute(String name) { return delegate.getAttribute(name); } /** * Format as CDL. * @param buf StringBuffer into which to write */ public void toCdl(StringBuffer buf) { delegate.toCdl(buf); } /** * @return a CDL string of this. */ public String toString() { StringBuffer buf = new StringBuffer(); toCdl(buf); return buf.toString(); } /** * Used to compute 'dimension index' needed * in netcdf version 1 files. */ int indexOf(Dimension dim) { return delegate.indexOf(dim); } /* implementation */ /** * Used when creating variables to populate this. * Override in your implementation to provide the * correct i/o functionality. */ protected abstract Accessor ioFactory(ProtoVariable proto) throws InvocationTargetException; /** * Used for incremental initialization. * Add a Dimension to the Netcdf. */ protected void putDimension(Dimension dim) { delegate.putDimension(dim); } /** * Used for incremental initialization. * Add a (global) attribute to the Netcdf. */ protected void putAttribute(Attribute attr) { delegate.putAttribute(attr); } /** * Used for incremental initialization. * Add a variable to the Netcdf. protected void put(ProtoVariable proto, Variable var) { if(!proto.getName().equals(var.getName())) throw new IllegalArgumentException( proto.getName() + " != " + var.getName()); delegate.put(proto); variables.put(var.getName(),var); } */ /** * Used for incremental initialization. * Add a variable to the Netcdf. */ protected void add(ProtoVariable proto, Accessor io) throws InstantiationException, InvocationTargetException, IllegalAccessException { delegate.put(proto); final Object [] args = {proto, io}; final Variable var = (Variable) ctor.newInstance(args); variables.put(var.getName(),var); } /* */ /** * These are the parameter types used for the * Variable constructor in <code>initHashtable(Class)</code> */ static final Class [] varCtorParameterTypes() { try { Class [] parameterTypes = { Class.forName("ucar.netcdf.ProtoVariable"), Class.forName("ucar.multiarray.Accessor") }; return parameterTypes; } catch (ClassNotFoundException cnfe) { // Shouldn't happen throw new Error( "ucar.netcdf implementation error"); } } protected void initHashtable() throws InstantiationException, InvocationTargetException, IllegalAccessException { for(ProtoVariableIterator iter = delegate.iterator(); iter.hasNext();) { final ProtoVariable proto = iter.next(); final Accessor io = ioFactory(proto); final Object [] args = {proto, io}; final Variable var = (Variable) ctor.newInstance(args); // assert(var.getName() == proto.getName()); if(variables.put(var.getName(), var) != null) throw new IllegalArgumentException( "Duplicate variable name"); } // assert(delegate.size() == variables.size(); } static private Constructor VariableCtor() { try { final Class vc = Class.forName("ucar.netcdf.Variable"); return vc.getDeclaredConstructor( varCtorParameterTypes() ); } catch (ClassNotFoundException cnfe) { // Can't happen: ucar.netcdf.Variable exists throw new Error(); } catch (NoSuchMethodException cnfe) { // Can't happen: ucar.netcdf.Variable has this ctor throw new Error(); } } /* package */ Schema getSchema() { return delegate; } final private Constructor ctor; final private Schema delegate; final private Hashtable variables; }