/* * AbstractDataSet.java * * Created on April 2, 2007, 8:55 AM * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package org.das2.qds; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.datum.Units; import org.das2.util.LoggerManager; /** * Abstract class to simplify defining datasets. This handles the * properties for implementations, and they * need only implement rank, and override the corresponding value and length * methods. * * @author jbf */ public abstract class AbstractDataSet implements QDataSet, MutablePropertyDataSet { private static final Logger logger= LoggerManager.getLogger("qdataset"); boolean hasIndexedProperties= false; protected HashMap properties; private boolean immutable= false; public AbstractDataSet() { properties= new HashMap<>(); } @Override public abstract int rank(); @Override public double value() { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public String svalue() { Units u= (Units) property(QDataSet.UNITS); if ( u==null ) { return String.valueOf(value()); } else { return u.createDatum(value()).toString(); } } @Override public double value(int i0) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public double value(int i0, int i1) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public double value(int i0, int i1, int i2) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public double value(int i0, int i1, int i2, int i3) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public Object property(String name) { return properties.get(name); } @Override public Object property(String name, int i) { Object r= null; if ( hasIndexedProperties ) { String pname= name + "__" + i; r= properties.get( pname ); } if ( r!=null ) { return r; } else { if ( DataSetUtil.isInheritedProperty(name) ) { return properties.get(name); } else { return null; } } } /** * print a warning message when the property is not the correct type. * @param name property name * @param value property value */ private static void checkPropertyType( String name, Object value ) { switch ( name ) { case QDataSet.DELTA_MINUS: case QDataSet.DELTA_PLUS: case QDataSet.BIN_MINUS: case QDataSet.BIN_PLUS: case QDataSet.WEIGHTS: if ( value!=null && !( value instanceof QDataSet ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a QDataSet (%s)", name, value.toString() ) ); } return; case QDataSet.DEPEND_0: case QDataSet.DEPEND_1: case QDataSet.DEPEND_2: case QDataSet.DEPEND_3: case QDataSet.BUNDLE_0: case QDataSet.BUNDLE_1: case QDataSet.BUNDLE_2: case QDataSet.BUNDLE_3: if ( value!=null && !( value instanceof QDataSet ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a QDataSet (%s)", name, value.toString() ) ); } return; case QDataSet.UNITS: if ( value!=null && !( value instanceof Units ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a Unit (%s)", name, value.toString() ) ); } return; case QDataSet.NAME: case QDataSet.LABEL: case QDataSet.TITLE: case QDataSet.FORMAT: case QDataSet.SCALE_TYPE: case QDataSet.METADATA_MODEL: case QDataSet.BINS_0: case QDataSet.BINS_1: if ( value!=null && !( value instanceof String ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a String (%s)", name, value.toString() ) ); } return; case QDataSet.VALID_MIN: case QDataSet.VALID_MAX: case QDataSet.TYPICAL_MIN: case QDataSet.TYPICAL_MAX: case QDataSet.FILL_VALUE: if ( value!=null && !( value instanceof Number ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a Number (%s)", name, value.toString() ) ); } return; case QDataSet.USER_PROPERTIES: case QDataSet.METADATA: if ( value!=null && !( value instanceof Map ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a Map (%s)", name, value.toString() ) ); } return; case QDataSet.QUBE: if ( value!=null && !( value instanceof Boolean ) ) { logger.warning( String.format( "AbstractDataSet.checkPropertyType: %s is not a Boolean (%s)", name, value.toString() ) ); } return; default: return; } } @Override public void putProperty( String name, Object value ) { checkImmutable(); String propCheckName= name; int i__= name.indexOf("__"); if ( i__>-1 ) { hasIndexedProperties= true; propCheckName= name.substring(0,i__); } if ( value!=null ) checkPropertyType( propCheckName, value ); if ( name.startsWith("DEPEND_") ) { if ( name.equals( QDataSet.DEPEND_0 ) && value!=null ) { if ( value instanceof QDataSet ) { // BUNDLES can have string value here QDataSet dep0= ((QDataSet)value); if ( this.rank()>0 && dep0.length()!=this.length() ) { logger.log(Level.WARNING, "DEPEND_0 is incorrect length, its length is {0} should be {1}", new Object[]{dep0.length(), this.length()}); } } else if ( value instanceof String ) { logger.warning("Use DEPENDNAME_0 instead of DEPEND_0"); } } else if ( name.equals( QDataSet.DEPEND_1 ) && value!=null ) { if ( this.rank()<=1 ) { logger.warning("DEPEND_1 was set on dataset of rank 0 or rank 1. Ignoring..."); } else { if ( value instanceof QDataSet ) { // BUNDLES can have string value here QDataSet dep1= ((QDataSet)value); if ( this.rank()>0 && this.length()>0 && dep1.rank()==1 && dep1.length()!=this.length(0) ) { logger.log(Level.WARNING, "DEPEND_1 is incorrect length, its length is {0} should be {1}", new Object[]{dep1.length(), this.length(0)}); } } else if ( value instanceof String ) { logger.warning("Use DEPENDNAME_1 instead of DEPEND_1"); } } } if ( ( name.charAt(7)-'0') > 0 ) { if ( value instanceof QDataSet ) { if ( ((QDataSet)value).rank()>1 ) { //Object o= properties.remove(QDataSet.QUBE); // BufferDataSet automatically sets QUBE to be true. //if ( o!=null ) { // logger.log(Level.FINER, "removing QUBE property (if any) because high rank {0}", name); //} logger.log(Level.FINER, "high rank 2 {0} might imply this is not a QUBE.", name); } } } } properties.put( name, value ); } @Override public void putProperty( String name, int index, Object value ) { checkImmutable(); hasIndexedProperties= true; properties.put( name + "__" + index, value ); } @Override public void makeImmutable() { immutable= true; } @Override public boolean isImmutable() { return this.immutable; } /** * Implementations should call this when attempts to modify the dataset * are performed, so that it is guaranteed that it is safe to modify. * This will throw an exception once things look stable. * Note there are scripts in the wild that abuse mutability that need to be * fixed before this can be done. */ protected final void checkImmutable() { if ( immutable ) { throw new IllegalArgumentException("dataset has been marked as immutable"); } } @Override public int length() { throw new IllegalArgumentException("rank error, rank 0 datasets have no length()"); } @Override public int length(int i0) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public int length(int i0, int i1) { throw new IllegalArgumentException("rank error, expected "+rank()); } @Override public int length(int i0, int i1, int i2) { throw new IllegalArgumentException("rank error, expected "+rank()+", NAME="+this.property(QDataSet.NAME) ); } @Override public T capability(Class clazz) { return null; } @Override public QDataSet slice(int i) { return new Slice0DataSet(this, i); } @Override public QDataSet trim(int start, int end) { if ( start==0 && end==length() ) { return this; } else { return new TrimDataSet( this, start, end ); } } /** * return a human-readable string representation of this QDataSet. * @return a human-readable string representation of this QDataSet. * @see org.das2.qds.DataSetUtil#toString(org.das2.qds.QDataSet) */ @Override public String toString( ) { return DataSetUtil.toString(this); } }