/*
* Copyright (c) 2012 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.io;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.dawnsci.analysis.api.io.IDataHolder;
import org.eclipse.dawnsci.analysis.api.io.IFileLoader;
import org.eclipse.dawnsci.analysis.api.tree.Tree;
import org.eclipse.january.MetadataException;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.ILazyDataset;
import org.eclipse.january.dataset.IMetadataProvider;
import org.eclipse.january.metadata.IMetadata;
import org.eclipse.january.metadata.Metadata;
import org.eclipse.january.metadata.MetadataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is to marshal all the data for the purpose of loading from or saving to a file
* directly or via a ScanFileHolder.
* <p>
* This is designed to take in any dataset obeying the IDataset interface but output an
* object that is a subclass of Dataset - the dataset will be converted if necessary.
*
* This implementation does not permit duplicated names.
*/
public class DataHolder implements IMetadataProvider, IDataHolder, Serializable {
protected static final Logger logger = LoggerFactory.getLogger(DataHolder.class);
/**
* List containing all the name and data pairs (to be) loaded.
*/
private LinkedHashMap<String, ILazyDataset> nameDataMappings;
/**
* List containing metadata
*/
private IMetadata metadata;
/**
* Loader class string
*/
private String loaderClass;
/**
* The path to the original file loaded (if any)
*/
private String filePath;
private Tree tree;
/**
* This must create the three objects which will be put into the ScanFileHolder
*/
public DataHolder() {
this(new Metadata());
}
/**
* Used to hold metadata
* @param meta
*/
public DataHolder(IMetadata meta) {
nameDataMappings = new LinkedHashMap<String, ILazyDataset>();
metadata = meta;
}
/**
* The current data as a map of lazy datasets.
* @return map of lazy datasets with keys from their corresponding names
*/
@Override
public Map<String, ILazyDataset> toLazyMap() {
return new LinkedHashMap<String, ILazyDataset>(nameDataMappings);
}
/**
* Does not clone the meta data.
* @return shallow copy of DataHolder
*/
@Override
public IDataHolder clone() {
DataHolder ret = new DataHolder();
ret.nameDataMappings.putAll(nameDataMappings);
ret.metadata = metadata;
ret.filePath = filePath;
ret.loaderClass = loaderClass;
return ret;
}
/**
* Adds an entry to the holder
*
* Replaces any datasets of the same name already existing.
*
* @param name
* the name of the dataset which is to be added
* @param dataset
* the actual data of the dataset
* @return true if this replaces an existing entry
*/
@Override
public boolean addDataset(String name, ILazyDataset dataset) {
boolean ret = nameDataMappings.containsKey(name);
nameDataMappings.put(name, dataset);
return ret;
}
/**
* Adds an entry with metadata
*
* Replaces any datasets of the same name already existing.
*
* @param name
* the name of the dataset which is to be added
* @param dataset
* the actual data of the dataset.
* @param metadata
* the metadata that is associated with the dataset
* @return true if this replaces an existing entry
*/
public boolean addDataset(String name, ILazyDataset dataset, IMetadata metadata) {
boolean ret = addDataset(name, dataset);
this.metadata = metadata;
return ret;
}
/**
* Add a ImetaData object
* @param metadata which is an object implementing IMetadata
*/
@Override
public void setMetadata(IMetadata metadata) {
this.metadata = metadata;
}
/**
* @return an object implementing IMetadata
*/
@Override
public IMetadata getMetadata() {
return metadata;
}
@SuppressWarnings("unchecked")
@Override
public <S extends MetadataType, T extends S> List<S> getMetadata(Class<T> clazz) throws MetadataException {
if (IMetadata.class.isAssignableFrom(clazz)) {
List<S> result = new ArrayList<S>();
result.add((S) getMetadata());
return result;
}
throw new MetadataException("getMetadata(clazz) does not currently support anything other than IMetadata");
// If it should only support this, simply return null here, otherwise implement the method fully
}
@Override
public <S extends MetadataType, T extends S> S getFirstMetadata(Class<T> clazz) {
try {
List<S> ml = getMetadata(clazz);
if (ml == null) return null;
return ml.isEmpty() ? null : ml.get(0);
} catch (Exception e) {
logger.error("Get metadata failed!",e);
}
return null;
}
/**
* @return List of (potential lazy) datasets
*/
@Override
public List<ILazyDataset> getList() {
return new ArrayList<ILazyDataset>(nameDataMappings.values());
}
/**
* This pulls out the dataset which could be lazy, maintaining its laziness.
* @param index
* @return dataset with given index in holder or null if it does not exist
*/
@Override
public ILazyDataset getLazyDataset(int index) {
final String key = getName(index);
if (key == null ) return null;
return nameDataMappings.get(key);
}
/**
* This pulls out the dataset which could be lazy, maintaining its laziness.
* @param name
* @return dataset with given name or null if it does not exist
*/
@Override
public ILazyDataset getLazyDataset(String name) {
return nameDataMappings.get(name);
}
/**
* Set a generic dataset with given name
* @param name
* @param dataset
*/
public void setDataset(String name, ILazyDataset dataset) {
nameDataMappings.put(name, dataset);
}
/**
* This does not retrieve lazy datasets.
* @param index
* @return Generic dataset with given index in holder or null if it is lazy or does not exist
*/
@Override
public Dataset getDataset(int index) {
ILazyDataset lazy = getLazyDataset(index);
return lazy instanceof IDataset ? DatasetUtils.convertToDataset((IDataset) lazy) : null;
}
/**
* This does not retrieve lazy datasets.
* @param name
* @return Generic dataset with given name or null if it is lazy or does not exist
*/
@Override
public Dataset getDataset(String name) {
ILazyDataset lazy = getLazyDataset(name);
return lazy instanceof IDataset ? DatasetUtils.convertToDataset((IDataset) lazy) : null;
}
/**
* @param name
* @return true if data holder contains name
* @see java.util.List#contains(Object)
*/
@Override
public boolean contains(String name) {
return nameDataMappings.containsKey(name);
}
/**
* @param name
* @return index of dataset with given name
* @see java.util.List#indexOf(Object)
*/
public int indexOf(String name) {
List<String> keys = new ArrayList<String>(nameDataMappings.keySet());
return keys.indexOf(name);
}
/**
* @return Array of dataset names
*/
@Override
public String[] getNames() {
return nameDataMappings.keySet().toArray(new String[nameDataMappings.size()]);
}
/**
* @param index
* @return Dataset name at given index
*/
@Override
public String getName(final int index) {
if (index < 0 || index >= size()) {
return null;
}
List<String> keys = new ArrayList<String>(nameDataMappings.keySet());
return keys.get(index);
}
/**
* @return Number of datasets
*/
@Override
public int size() {
return nameDataMappings.size();
}
/**
* @return Number of unique dataset names
*/
@Deprecated
@Override
public int namesSize() {
return size();
}
/**
* Clear list of names and datasets
* @see java.util.List#clear()
*/
@Override
public void clear() {
nameDataMappings.clear();
metadata = null;
tree = null;
}
/**
* Remove name and dataset at index
* @param index
* @see java.util.List#remove(int)
*/
public void remove(int index) {
final String key = getName(index);
if (key != null)
nameDataMappings.remove(key);
}
/**
* @return class of file loader or null if class is not found by class loader
*/
@Override
@SuppressWarnings("unchecked")
public Class<? extends IFileLoader> getLoaderClass() {
if (loaderClass == null)
return null;
try {
return (Class<? extends AbstractFileLoader>) Class.forName(loaderClass);
} catch (ClassNotFoundException e) {
logger.error("No class found for {}", loaderClass, e);
}
return null;
}
@Override
public void setLoaderClass(Class<? extends IFileLoader> clazz) {
loaderClass = clazz.getName();
}
@Override
public String getFilePath() {
return filePath;
}
@Override
public void setFilePath(String filePath) {
this.filePath = filePath;
}
@Override
public void setTree(Tree tree) {
this.tree = tree;
}
@Override
public Tree getTree() {
return tree;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((filePath == null) ? 0 : filePath.hashCode());
result = prime * result + ((loaderClass == null) ? 0 : loaderClass.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((nameDataMappings == null) ? 0 : nameDataMappings.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DataHolder other = (DataHolder) obj;
if (filePath == null) {
if (other.filePath != null)
return false;
} else if (!filePath.equals(other.filePath))
return false;
if (loaderClass == null) {
if (other.loaderClass != null)
return false;
} else if (!loaderClass.equals(other.loaderClass))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
return false;
if (nameDataMappings == null) {
if (other.nameDataMappings != null)
return false;
} else if (!nameDataMappings.equals(other.nameDataMappings))
return false;
return true;
}
@Override
public String toString() {
return nameDataMappings.toString();
}
}