//
// NetCDFServiceImpl.java
//
/*
OME Bio-Formats package for reading and converting biological file formats.
Copyright (C) 2005-@year@ UW-Madison LOCI and Glencoe Software, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package loci.formats.services;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import loci.common.Location;
import loci.common.services.AbstractService;
import loci.common.services.ServiceException;
import ucar.ma2.Array;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.Attribute;
import ucar.nc2.Group;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
/**
* Utility class for working with NetCDF/HDF files. Uses reflection to
* call the NetCDF Java library.
*
* <dl><dt><b>Source code:</b></dt>
* <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/services/NetCDFServiceImpl.java">Trac</a>,
* <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/services/NetCDFServiceImpl.java;hb=HEAD">Gitweb</a></dd></dl>
*/
public class NetCDFServiceImpl extends AbstractService
implements NetCDFService {
// -- Constants --
public static final String NO_NETCDF_MSG =
"NetCDF is required to read NetCDF/HDF variants. " +
"Please obtain the necessary JAR files from " +
"http://loci.wisc.edu/bio-formats/bio-formats-java-library.\n" +
"Required JAR files are netcdf-4.0.jar and slf4j-jdk14.jar.";
// -- Fields --
private String currentFile;
private Vector<String> attributeList;
private Vector<String> variableList;
/** NetCDF file instance. */
private NetcdfFile netCDFFile;
/** Root of the NetCDF file. */
private Group root;
// -- NetCDFService API methods ---
/**
* Default constructor.
*/
public NetCDFServiceImpl() {
// One check from each package
checkClassDependency(ucar.nc2.Attribute.class);
checkClassDependency(ucar.ma2.Array.class);
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#setFile(java.lang.String)
*/
public void setFile(String file) throws IOException {
this.currentFile = file;
String currentId = Location.getMappedId(currentFile);
netCDFFile = NetcdfFile.open(currentId);
root = netCDFFile.getRootGroup();
attributeList = new Vector<String>();
variableList = new Vector<String>();
List<Group> groups = new ArrayList<Group>();
groups.add(root);
parseAttributesAndVariables(groups);
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getFile()
*/
public String getFile() {
return currentFile;
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getAttributeList()
*/
public Vector<String> getAttributeList() {
return attributeList;
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getVariableList()
*/
public Vector<String> getVariableList() {
return variableList;
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getAttributeValue(java.lang.String)
*/
public String getAttributeValue(String path) {
String groupName = getDirectory(path);
String attributeName = getName(path);
Group group = getGroup(groupName);
Attribute attribute = group.findAttribute(attributeName);
if (attribute == null) return null;
return arrayToString(attribute.getValues());
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getVariableValue(java.lang.String)
*/
public Object getVariableValue(String name) throws ServiceException {
return getArray(name, null, null);
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getArray(java.lang.String, int[], int[])
*/
public Object getArray(String path, int[] origin, int[] shape)
throws ServiceException
{
String groupName = getDirectory(path);
String variableName = getName(path);
Group group = getGroup(groupName);
Variable variable = group.findVariable(variableName);
try {
if (origin != null && shape != null) {
return variable.read(origin, shape).reduce().copyToNDJavaArray();
}
return variable.read().copyToNDJavaArray();
}
catch (InvalidRangeException e) {
throw new ServiceException(e);
}
catch (IOException e) {
throw new ServiceException(e);
}
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#getVariableAttributes(java.lang.String)
*/
public Hashtable<String, Object> getVariableAttributes(String name) {
String groupName = getDirectory(name);
String variableName = getName(name);
Group group = getGroup(groupName);
Variable variable = group.findVariable(variableName);
List<Attribute> attributes = variable.getAttributes();
Hashtable<String, Object> toReturn = new Hashtable<String, Object>();
for (Attribute attribute: attributes) {
toReturn.put(attribute.getName(), arrayToString(attribute.getValues()));
}
return toReturn;
}
public int getDimension(String name) {
String groupName = getDirectory(name);
String variableName = getName(name);
Group group = getGroup(groupName);
return group.findDimension(variableName).getLength();
}
/* (non-Javadoc)
* @see loci.formats.NetCDFService#close()
*/
public void close() throws IOException {
if (netCDFFile != null) netCDFFile.close();
currentFile = null;
attributeList = null;
variableList = null;
netCDFFile = null;
root = null;
}
// -- Helper methods --
/**
* Recursively parses attribute and variable paths, filling
* <code>attributeList</code> and <code>variableList</code>.
* @param groups List of groups to recursively parse.
*/
private void parseAttributesAndVariables(List<Group> groups) {
for (Group group : groups) {
String groupName = group.getName();
List<Attribute> attributes = group.getAttributes();
for (Attribute attribute : attributes) {
String attributeName = attribute.getName();
if (!groupName.endsWith("/")) attributeName = "/" + attributeName;
attributeList.add(groupName + attributeName);
}
List<Variable> variables = group.getVariables();
for (Variable variable : variables) {
String variableName = variable.getName();
if (!groupName.endsWith("/")) variableName = "/" + variableName;
variableList.add(variableName);
}
groups = group.getGroups();
parseAttributesAndVariables(groups);
}
}
/**
* Retrieves a group based on its fully qualified path.
* @param path Fully qualified path to the group.
* @return Group or <code>root</code> if the group cannot be found.
*/
private Group getGroup(String path) {
if (path.indexOf("/") == -1) {
return root;
}
StringTokenizer tokens = new StringTokenizer(path, "/");
Group parent = root;
while (tokens.hasMoreTokens()) {
parent = parent.findGroup(tokens.nextToken());
}
return parent == null? root : parent;
}
private String getDirectory(String path) {
return path.substring(0, path.lastIndexOf("/"));
}
private String getName(String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
private String arrayToString(Array values) {
Object v = values.copyTo1DJavaArray();
if (v instanceof Object[]) {
Object[] array = (Object[]) v;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; i++) {
sb.append((String) array[i]);
}
return sb.toString().trim();
}
return values.toString().trim();
}
}