// FileFlatField.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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 visad.data;
import java.io.IOException;
import java.rmi.RemoteException;
import visad.FlatField;
import visad.*;
public class FileFlatField extends FlatField {
// note FileFlatField extends FlatField but may not inherit
// any of its methods - it must re-implement all of them
// through the adapted FlatField
// number of FlatFields in cache
private static final int MAX_FILE_FLAT_FIELDS = 10;
// array of cached FlatFields
private static transient FlatField[] adaptedFlatFields =
new FlatField[MAX_FILE_FLAT_FIELDS];
// true if cache entry differs from file contents
private static transient boolean adaptedFlatFieldDirty[] =
new boolean[MAX_FILE_FLAT_FIELDS];
// the FileFlatField that owns this cache entry
private static transient FileFlatField[] adaptedFlatFieldOwner =
new FileFlatField[MAX_FILE_FLAT_FIELDS];
// adaptedFlatFieldSizes and adaptedFlatFieldTimes
// may be useful for cache allocation algorithms
// approximate sizes of FlatFields in cache
private static transient long[] adaptedFlatFieldSizes =
new long[MAX_FILE_FLAT_FIELDS];
// times of most recent accesses to FlatFields in cache
private static transient long[] adaptedFlatFieldTimes =
new long[MAX_FILE_FLAT_FIELDS];
// index of cache entry owned by this FileFlatField;
// but only if
// this == adaptedFlatFieldOwner[adaptedFlatFieldIndex]
private transient int adaptedFlatFieldIndex;
// this is the FileAccessor for reading and writing values from
// and to the adapted file
transient FileAccessor fileAccessor;
// this implements a strategy for cache replacement;
// this separates the cahce strategy algorithm from the logic
// of FileFlatField
private transient CacheStrategy cacheStrategy;
static
{
// initialize cache of FlatFields
if (adaptedFlatFieldOwner != null && adaptedFlatFields != null &&
adaptedFlatFieldSizes != null && adaptedFlatFieldTimes != null &&
adaptedFlatFieldDirty != null) {
for (int i=0; i<MAX_FILE_FLAT_FIELDS; i++) {
// mark Owners for all cache entries to indicate not
// belonging to any FileFlatField
adaptedFlatFieldOwner[i] = null;
adaptedFlatFields[i] = null;
adaptedFlatFieldSizes[i] = 0;
adaptedFlatFieldTimes[i] = System.currentTimeMillis();
adaptedFlatFieldDirty[i] = false;
}
}
}
// all methods lock on adaptedFlatFields cache
// to ensure thread safe access
public FileFlatField( FileAccessor accessor, CacheStrategy strategy )
throws VisADException
{
super( accessor.getFunctionType(),
getNullDomainSet(accessor.getFunctionType().getDomain()) );
fileAccessor = accessor;
cacheStrategy = strategy;
// '0' is in legal range of adaptedFlatFieldIndex,
// but not owned by this
adaptedFlatFieldIndex = 0;
}
private static Set getNullDomainSet(RealTupleType type)
throws VisADException {
int n = type.getDimension();
double[] values = new double[n];
for (int i=0; i<n; i++) values[i] = 0.0;
RealTuple tuple;
try {
tuple = new RealTuple(type, values);
return new SingletonSet(tuple);
}
catch (RemoteException e) {
throw new VisADError("FileFlatField.getNullDomainSet: " + e.toString());
}
}
private FlatField getAdaptedFlatField()
{
// if owner array is null,
// assume this object got serialized & unserialized
if (adaptedFlatFieldOwner == null) {
return null;
}
synchronized (adaptedFlatFields) {
for ( int ii = 0; ii < MAX_FILE_FLAT_FIELDS; ii++ )
{
if (this == adaptedFlatFieldOwner[ii]) {
// mark time of most recent access
adaptedFlatFieldTimes[ii] = System.currentTimeMillis();
return adaptedFlatFields[ii];
}
}
// this FileFlatField does not own a cache entry, so invoke
// CahceStrategy.allocate to allocate one, possibly by taking
// one, possibly by taking one from another FileFlatField;
// this will be an area for lots of thought and experimentation;
adaptedFlatFieldIndex =
cacheStrategy.allocate(adaptedFlatFields, adaptedFlatFieldDirty,
adaptedFlatFieldSizes, adaptedFlatFieldTimes);
// flush cache entry, if dirty
if (adaptedFlatFieldDirty[adaptedFlatFieldIndex])
{
try
{
adaptedFlatFieldOwner[adaptedFlatFieldIndex].flushCache();
}
catch ( VisADException e )
{
System.out.println( e.getMessage() );
}
}
// create a new entry in adaptedFlatFields at adaptedFlatFieldIndex
// and read data values from fileAccessor at fileLocation
try
{
adaptedFlatFields[adaptedFlatFieldIndex] = fileAccessor.getFlatField();
}
catch ( VisADException e1 )
{
System.out.println( e1.getMessage() );
}
catch ( RemoteException e2 )
{
System.out.println( e2.getMessage() );
}
// mark cache entry as belonging to this FileFlatField
adaptedFlatFieldOwner[adaptedFlatFieldIndex] = this;
// get size of adapted FlatField
// (by calling a method that currently does not exist)
/*adaptedFlatFields[adaptedFlatFieldIndex].getSize(); */
adaptedFlatFieldTimes[adaptedFlatFieldIndex] =
System.currentTimeMillis();
return adaptedFlatFields[adaptedFlatFieldIndex];
}
}
private void flushCache()
throws VisADException
{
if (adaptedFlatFields == null) {
throw new VisADException("Cannot access serialized FileFlatField");
}
// make sure this owns cache entry
if (this == adaptedFlatFieldOwner[adaptedFlatFieldIndex]) {
// unpackValues is currently private, would need default protection
// for access from FileFlatField
/* fileAccessor.writeFlatField(
adaptedFlatFields[adaptedFlatFieldIndex].unpackValues(),
templateFlatField, fileLocation); */
}
}
// must implement all the methods of Data, Function and Field
//
// most are simple adapters, like this:
//
public Data getSample(int index)
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.getSample(index);
}
public int getLength()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return 0;
}
return fld.getLength();
}
public Unit[] getDomainUnits()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getDomainUnits();
}
public CoordinateSystem getDomainCoordinateSystem()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getDomainCoordinateSystem();
}
public CoordinateSystem[] getRangeCoordinateSystem()
throws TypeException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getRangeCoordinateSystem();
}
public CoordinateSystem[] getRangeCoordinateSystem( int component )
throws TypeException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getRangeCoordinateSystem( component );
}
public Unit[][] getRangeUnits()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getRangeUnits();
}
public Unit[] getDefaultRangeUnits()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getDefaultRangeUnits();
}
public double[][] getValues()
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.getValues();
}
public double[][] getValues(boolean copy)
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.getValues(copy);
}
public double[] getValues(int index)
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.getValues(index);
}
public float[][] getFloats(boolean copy)
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.getFloats(copy);
}
public Set getDomainSet()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.getDomainSet();
}
// setSample is typical of methods that involve changing the
// contents of this Field
public void setSample(int index, Data range)
throws VisADException, RemoteException {
if (adaptedFlatFields == null) {
throw new VisADException("Cannot access serialized FileFlatField");
}
synchronized (adaptedFlatFields) {
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
adaptedFlatFieldDirty[adaptedFlatFieldIndex] = true;
fld.setSample(index, range);
}
}
public void setSample( RealTuple domain, Data range )
throws VisADException, RemoteException
{
if (adaptedFlatFields == null) {
throw new VisADException("Cannot access serialized FileFlatField");
}
synchronized (adaptedFlatFields)
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
adaptedFlatFieldDirty[adaptedFlatFieldIndex] = true;
fld.setSample( domain, range );
}
}
public void setSample( int index, Data range, boolean copy )
throws VisADException, RemoteException
{
if (adaptedFlatFields == null) {
throw new VisADException("Cannot access serialized FileFlatField");
}
synchronized (adaptedFlatFields)
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
adaptedFlatFieldDirty[adaptedFlatFieldIndex] = true;
fld.setSample( index, range, copy );
}
}
public boolean isMissing()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return true;
}
return fld.isMissing();
}
public Data binary( Data data, int op, int sampling_mode, int error_mode )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.binary( data, op, sampling_mode, error_mode);
}
public Data binary( Data data, int op, MathType new_type, int sampling_mode, int error_mode )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.binary( data, op, new_type, sampling_mode, error_mode);
}
public Data unary( int op, int sampling_mode, int error_mode )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.unary( op, sampling_mode, error_mode );
}
public Data unary(int op, MathType new_type, int sampling_mode, int error_mode)
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.unary(op, new_type, sampling_mode, error_mode);
}
/** unpack an array of doubles from field sample values according to the
RangeSet-s; returns a copy */
public double[][] unpackValues() throws VisADException {
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.unpackValues();
}
/** unpack an array of floats from field sample values according to the
RangeSet-s; returns a copy */
public float[][] unpackFloats() throws VisADException {
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.unpackFloats();
}
public Field extract( int component )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.extract( component );
}
public Field domainFactor( RealType factor )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.domainFactor( factor );
}
public Field resample( Set set, int sampling_mode, int error_mode )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.resample( set, sampling_mode, error_mode );
}
public DataShadow computeRanges(ShadowType type, DataShadow shadow)
throws VisADException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.computeRanges( type, shadow );
}
public Data adjustSamplingError( Data error, int error_mode )
throws VisADException, RemoteException
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
throw new VisADException("Cannot get cached FlatField");
}
return fld.adjustSamplingError( error, error_mode );
}
public boolean isFlatField()
{
return true;
}
/**
* Clones this instance. This implementation violates the general <code>
* clone()</code> contract in that the returned object will compare unequal to
* this instance. As such, this method should probably not be invoked.
*
* @return A clone of this instance.
*/
public Object clone()
{
/*
* This implementation should probably just throw a
* CloneNotSupportedException but can't because FlatField.clone() doesn't.
*/
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return null;
}
return fld.clone();
}
public String toString()
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return "Cannot get cached FlatField";
}
return fld.toString();
}
public String longString(String pre)
{
FlatField fld = getAdaptedFlatField();
if (fld == null) {
return pre + "Cannot get cached FlatField";
}
try {
return fld.longString(pre);
} catch (VisADException e) {
return pre + e.getMessage();
}
}
private void readObject(java.io.ObjectInputStream oos)
throws ClassNotFoundException, IOException
{
throw new java.io.NotSerializableException("FileFlatField is not serializable");
}
private void writeObject(java.io.ObjectOutputStream oos)
throws IOException
{
throw new java.io.NotSerializableException("FileFlatField is not serializable");
}
}