// $Id: Schema.java,v 1.5 2002-05-29 18:31:37 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 java.io.Serializable; /** * Schema collects the metadata which describes or defines a Netcdf. * This is a set of ProtoVariable, the DimensionSet which is * the union of the Dimensions used, and any global Attributes. * <p> * Instances are used as templates in creation of new Netcdf datasets. * <p> * Variable descriptions in form of ProtoVariable instances can be * added to, overwritten, or deleted from a Schema. The associated set of * global attributes may also be modified. * * @see ProtoVariable * @see DimensionSet * @see AttributeSet * @see Netcdf * @see java.util.Collection * * @author $Author: steve $ * @version $Revision: 1.5 $ $Date: 2002-05-29 18:31:37 $ */ public class Schema implements java.io.Serializable { /** * Create an empty Schema */ public Schema() { this.variables = new NamedDictionary(0); this.dimensions = new DimensionDictionary(); this.attributes = new AttributeDictionary(); } /** * Copy constructor. * @param sc Schema to copy from. May be empty, shouldn't be null. */ public Schema(Schema sc) { // Use clone instead?? synchronized (sc) { this.dimensions = new DimensionDictionary(sc.getDimensions()); this.variables = new NamedDictionary(sc.size()); for(ProtoVariableIterator iter = sc.iterator(); iter.hasNext();) { if(this.put(new ProtoVariable(iter.next())) != null) throw new IllegalArgumentException( "Duplicate variable name"); } this.attributes = new AttributeDictionary(sc.getAttributes()); } } /** * Create a Schema initialized by an existing Netcdf. * <p> * This would be the first step in making a copy of * a Netcdf, making a partial copy, or using and existing * Netcdf basis for another. * @param nc Netcdf from which to generate the Schema. */ public Schema(Netcdf nc) { this.dimensions = new DimensionDictionary(nc.getDimensions()); this.variables = new NamedDictionary(nc.size()); for(VariableIterator iter = nc.iterator(); iter.hasNext();) { if(this.put(new ProtoVariable(iter.next())) != null) throw new IllegalArgumentException( "Duplicate variable name"); } this.attributes = new AttributeDictionary(nc.getAttributes()); } /** * Create a Schema initialized by an array of ProtoVariable * and an array of Attributes. * @param varArray ProtoVariable [] to initialize the Schema. * May be null or length 0. * @param attrArray ProtoVariable [] to initialize the (global) Attributes. * May be null or length 0. */ public Schema(ProtoVariable [] varArray, Attribute [] attrArray) { if(varArray == null) { this.variables = new NamedDictionary(0); this.dimensions = new DimensionDictionary(); } else synchronized (varArray) { this.dimensions = new DimensionDictionary(varArray); this.variables = new NamedDictionary(varArray); } this.attributes = new AttributeDictionary(attrArray); } /* Begin ProtoVariableSet */ /** * Returns the number of ProtoVariable objects in this set * @return int number of elements in the set */ public int size() { return variables.size(); } /** * Returns ProtoVariableIterator for the elements. * @return ProtoVariableIterator for the elements. * @see ProtoVariableIterator */ public ProtoVariableIterator iterator() { return new ProtoVariableIterator() { final java.util.Enumeration ee = variables.elements(); public boolean hasNext() { return ee.hasMoreElements(); } public ProtoVariable next() { return (ProtoVariable) ee.nextElement(); } }; } /** * Returns a new Array containing the elements of this set. * @return a new Array containing the elements of this set. */ public ProtoVariable [] toArray() { final ProtoVariable [] aa = new ProtoVariable[this.size()]; final ProtoVariableIterator ee = this.iterator(); for(int ii = 0; ee.hasNext(); ii++) aa[ii] = ee.next(); return aa; } /** * 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 ProtoVariable get(String name) { return (ProtoVariable) variables.get(name); } /** * Tests if the ProtoVariable 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 ProtoVariable. */ public boolean contains(String name) { return variables.contains(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); } /** * Ensures that this set contains the specified ProtoVariable. * If a different ProtoVariable with the same name, was in the set, * it is returned, otherwise null is returned. * * @param var the ProtoVariable to be added to this set. * @return ProtoVariable replaced or null if not a replacement */ public synchronized ProtoVariable put(ProtoVariable var) { final ProtoVariable hit = this.get(var.getName()); if(hit != null) { if(hit == var) return null; // Nothing to do // else this.remove(hit); } variables.put(var); var.connectDims(dimensions); return hit; } /** * Delete the ProtoVariable specified by name from this set. * * @param name String identifying the ProtoVariable to be removed. * @return true if the Set changed as a result of this call. */ public synchronized boolean remove(String name) { final ProtoVariable var = (ProtoVariable) variables.remove(name); if(var == null) return false; // not found // else, reconcile dimensions // TODO: better algorithm for(DimensionIterator checkiter = var.getDimensionIterator(); checkiter.hasNext();) { boolean hit = false; final Dimension check = checkiter.next(); final String checkStr = check.getName(); for(ProtoVariableIterator viter = this.iterator(); viter.hasNext();) { for(DimensionIterator diter = viter.next().getDimensionIterator(); diter.hasNext();) { final Dimension ref = diter.next(); if(ref.getName().equals(checkStr)) { hit = true; break; } } if(hit) break; } if(!hit) dimensions.remove(checkStr); } return true; } /** * Delete the ProtoVariable specified from this set. * * @param oo ProtoVariable to be removed. * @return true if the Set changed as a result of this call. */ public boolean remove(Object oo) { if(this.contains(oo)) { return this.remove(((Named)oo).getName()); } return false; } /* End ProtoVariableSet */ /* Begin VSMixIn */ /** * 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 (DimensionSet) dimensions; } /** * 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 (AttributeSet) attributes; } /** * 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 attributes.get(name); } /* End VSMixIn */ /** * Convenience function; add global attribute. * @see AttributeSet#put * @param attr the Attribute to be added to this set. * @return Attribute replaced or null if not a replacement */ public Attribute putAttribute(Attribute attr) { return attributes.put(attr); } /** * Format as CDL. * @param buf StringBuffer into which to write */ public void toCdl(StringBuffer buf) { buf.append("{\n"); dimensions.toCdl(buf); buf.append("variables:\n"); for (ProtoVariableIterator iter = this.iterator(); iter.hasNext() ;) { buf.append("\t"); iter.next().toCdl(buf); } if(attributes.size() > 0) { buf.append("\n// global attributes:\n"); attributes.toCdl(buf); } buf.append("\n}"); } /** * @return a CDL string of this. */ public String toString() { StringBuffer buf = new StringBuffer(); toCdl(buf); return buf.toString(); } int indexOf(Dimension dim) { return dimensions.indexOf(dim); } void putDimension(Dimension dim) { dimensions.initialPut(dim); } /** * @serial */ private final DimensionDictionary dimensions; /** * @serial */ private final AttributeDictionary attributes; /** * @serial */ private final NamedDictionary variables; }