/*
* Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.server.opendap;
import opendap.dap.InvalidDimensionException;
import ucar.ma2.*;
import ucar.nc2.*;
import opendap.servers.*;
import opendap.dap.BaseType;
import opendap.dap.DArrayDimension;
import opendap.dap.PrimitiveVector;
import java.io.IOException;
import java.io.EOFException;
import java.io.DataOutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Wraps a netcdf variable with rank > 0 as an SDArray.
* For char arrays, use NcSDString (rank 0 or 1) or NcSDCharArray (rank > 1).
*
* @author jcaron
* @see NcSDCharArray
*/
public class NcSDArray extends SDArray implements HasNetcdfVariable {
static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NcSDArray.class);
private static final boolean debug = false, debugRead = false;
private Variable ncVar = null;
//ignore protected BaseType elemType;
/**
* Constructor: Wraps a netcdf variable in a DODS SDArray.
*
* @param v : netcdf Variable
* @param bt : DODS element type
*/
NcSDArray(Variable v, BaseType bt) {
super(Variable.getDAPName(v));
this.ncVar = v;
// set dimensions
for (Dimension dim : v.getDimensions()) {
appendDim(dim.getLength(), dim.getShortName());
}
// this seems to be how you set the type
// it creates the "primitive vector"
addVariable(bt);
// ignore this.elemType = bt;
}
public Variable getVariable() {
return ncVar;
}
/**
* Read the data values (parameters are ignored).
* Use the start, stop and stride values, typically set by the constraint evaluator.
*
* @param datasetName not used
* @param specialO not used
* @return false (no more data to be read)
* @throws IOException
* @throws EOFException
*/
public boolean read(String datasetName, Object specialO) throws IOException {
long tstart = System.currentTimeMillis();
Array a;
try {
if (log.isDebugEnabled())
log.debug(getRequestedRange());
// set up the netcdf read
int n = numDimensions();
List<Range> ranges = new ArrayList<>(n);
for (int i = 0; i < n; i++)
ranges.add(new Range(getStart(i), getStop(i), getStride(i)));
try {
a = ncVar.read(ranges);
} catch (java.lang.ArrayIndexOutOfBoundsException t) {
log.error(getRequestedRange(), t);
throw new RuntimeException("NcSDArray java.lang.ArrayIndexOutOfBoundsException=" + t.getMessage()+
" for request= "+ getRequestedRange()+" dataset= "+ datasetName, t);
}
if (debug)
System.out.println(" NcSDArray Read " + getEncodedName() + " " + a.getSize() + " elems of type = " + a.getElementType());
if (debugRead) System.out.println(" Read = " + a.getSize() + " elems of type = " + a.getElementType());
if (log.isDebugEnabled()) {
long tookTime = System.currentTimeMillis() - tstart;
log.debug("NcSDArray read array: " + tookTime * .001 + " seconds");
}
} catch (InvalidDimensionException e) {
log.error(getRequestedRange(), e);
throw new IllegalStateException("NcSDArray InvalidDimensionException=" + e.getMessage());
} catch (InvalidRangeException e) {
log.error(getRequestedRange(), e);
throw new IllegalStateException("NcSDArray InvalidRangeException=" + e.getMessage());
}
setData(a);
if (debugRead) System.out.println(" PrimitiveVector len = " + getPrimitiveVector().getLength() +
" type = " + getPrimitiveVector().getTemplate());
return (false);
}
private String getRequestedRange() {
try {
StringBuilder sbuff = new StringBuilder();
sbuff.append("NcSDArray read " + ncVar.getFullName());
for (int i = 0; i < numDimensions(); i++) {
DArrayDimension d = getDimension(i);
sbuff.append(" " + d.getEncodedName() + "(" + getStart(i) + "," + getStride(i) + "," + getStop(i) + ")");
}
return sbuff.toString();
} catch (InvalidDimensionException e) {
e.printStackTrace();
return e.getMessage();
}
}
public void setData(Array data) {
PrimitiveVector pv = getPrimitiveVector();
if (debugRead)
System.out.println(" PrimitiveVector type = " + pv.getTemplate() +
" pv type = " + pv.getClass().getName());
if (ncVar.getDataType() == DataType.STRING) {
int size = (int) data.getSize();
NcSDString[] dodsBT = new NcSDString[size];
IndexIterator ii = data.getIndexIterator();
int count = 0;
while (ii.hasNext()) {
dodsBT[count++] = new NcSDString(Variable.getDAPName(ncVar), (String) ii.getObjectNext());
}
pv.setInternalStorage(dodsBT);
} else if (ncVar.getDataType() == DataType.STRUCTURE) {
NcSDStructure sds = (NcSDStructure) pv.getTemplate();
int size = (int) data.getSize();
NcSDStructure[] dodsBT = new NcSDStructure[size];
IndexIterator ii = data.getIndexIterator();
int count = 0;
while (ii.hasNext()) {
StructureData sdata = (StructureData) ii.getObjectNext();
dodsBT[count] = new NcSDStructure(sds, sdata); // stupid replication - need to override externalize
count++;
}
pv.setInternalStorage(dodsBT);
} else {
// copy the data into the PrimitiveVector
// this is optimized to (possibly) eliminate the copy
Object pa = data.get1DJavaArray(data.getElementType());
pv.setInternalStorage(pa);
}
setRead(true);
}
public void serialize(DataOutputStream sink, StructureData sdata, StructureMembers.Member m) throws IOException {
long tstart = System.currentTimeMillis();
setData(sdata.getArray(m));
externalize(sink);
if (log.isDebugEnabled()) {
long tookTime = System.currentTimeMillis() - tstart;
log.debug("NcSDArray serialize: " + tookTime * .001 + " seconds");
}
}
}