Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jcamp.parser.JCAMPBlock Maven / Gradle / Ivy
package org.jcamp.parser;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jcamp.spectrum.ISpectrumIdentifier;
/**
* class for handling JCAMP blocks.
*
* @author Thomas Weber
*/
public class JCAMPBlock {
private ASDFDecoder asdfDecoder = new ASDFDecoder();
private static Log log = LogFactory.getLog(JCAMPBlock.class);
private final static IErrorHandler DEFAULT_ERROR_HANDLER = new ErrorHandlerAdapter() {
@Override
public void fatal(String msg) throws JCAMPException {
log.fatal(msg);
throw new JCAMPException("FATAL ERROR! " + msg);
}
@Override
public void error(String msg) throws JCAMPException {
log.error(msg);
throw new JCAMPException("ERROR! " + msg);
}
@Override
public void warn(String msg) throws JCAMPException {
log.warn(msg);
}
};
private IErrorHandler errorHandler = DEFAULT_ERROR_HANDLER;
public final static class Type implements Serializable {
private static final long serialVersionUID = -8081269600789693382L;
private final String key;
private final int ordinal;
private Type(int ordinal, String key) {
this.ordinal = ordinal;
this.key = key;
}
@Override
public String toString() {
return key;
}
public Collection types() {
return TYPES_LIST;
}
private Object readResolve() throws java.io.ObjectStreamException {
return TYPES[ordinal];
}
@Override
public final int hashCode() {
return ordinal;
}
@Override
public final boolean equals(Object obj) {
if (obj instanceof Type && ((Type) obj) == this)
return true;
return false;
}
public final static Type LINK = new Type(0, "link");
public final static Type STRUCTURE = new Type(1, "structure");
public final static Type FULLSPECTRUM = new Type(2, "full spectrum");
public final static Type PEAKTABLE = new Type(3, "peak table");
public final static Type ASSIGNMENT = new Type(4, "assignment");
private final static Type[] TYPES = new Type[] { LINK, STRUCTURE, FULLSPECTRUM, PEAKTABLE, ASSIGNMENT };
private final static List TYPES_LIST = Collections.unmodifiableList(Arrays.asList(TYPES));
}
private final static String CRLF = "\r\n";
private final int start;
private final int end;
private final String jcamp;
private final JCAMPBlock parent;
private int numDataRecords;
private Type type;
private int spectrumID;
private String data;
private Hashtable childBlocks = new Hashtable(10);
// hashtable containing all data records (or list of data records for multiple records with same key)
private Hashtable dataRecords = new Hashtable(50);
// array of data records with duplicate keys
private JCAMPDataRecord[] ldrs;
private JCAMPBlock[] references = null;
private boolean ntupleBlock = false;
private JCAMPNTuple ntuple;
private JCAMPVariable[] vars = null;
private boolean isValidating=true;
/**
* create JCAMPBlock from substring.
*/
public JCAMPBlock(JCAMPBlock parent, String jcamp, int start, int end) throws JCAMPException {
super();
this.jcamp = jcamp;
this.start = start;
this.end = end;
this.parent = parent;
initBlocks();
initLDRs();
analyzeBlockType();
initNTuple();
initVariables();
}
/**
* create JCAMPBlock from substring.
*/
public JCAMPBlock(JCAMPBlock parent, String jcamp, int start, int end, IErrorHandler errorHandler)
throws JCAMPException {
super();
this.jcamp = jcamp;
this.start = start;
this.end = end;
this.parent = parent;
this.errorHandler = errorHandler;
initBlocks();
initLDRs();
analyzeBlockType();
initNTuple();
initVariables();
}
/**
* create JCAMPBlock from String
* @param jcamp java.lang.String
*/
public JCAMPBlock(String jcamp) throws JCAMPException {
this(jcamp, 0, jcamp.length());
}
/**
* create JCAMPBlock from substring.
*/
public JCAMPBlock(String jcamp, int start, int end) throws JCAMPException {
this(null, jcamp, start, end);
}
/**
* create JCAMPBlock from substring.
*/
public JCAMPBlock(String jcamp, int start, int end, IErrorHandler errorHandler) throws JCAMPException {
this(null, jcamp, start, end, errorHandler);
}
/**
* create JCAMPBlock from String
* @param jcamp java.lang.String
*/
public JCAMPBlock(String jcamp, IErrorHandler errorHandler) throws JCAMPException {
this(jcamp, 0, jcamp.length(), errorHandler);
}
/**
* analyze data records for type of block.
*/
private void analyzeBlockType() throws JCAMPException {
JCAMPDataRecord ldrJCAMPCS = getDataRecord("JCAMPCS");
if (ldrJCAMPCS != null)
this.type = Type.STRUCTURE;
else {
JCAMPDataRecord ldrDataType = getDataRecord("DATATYPE");
if (ldrDataType == null)
throw new JCAMPException("missing ##DATATYPE=");
String dtype = ldrDataType.getContent().toUpperCase();
if (dtype.indexOf("LINK") >= 0) {
this.type = Type.LINK;
} else if (dtype.indexOf("TABLE") >= 0) {
this.type = Type.PEAKTABLE;
analyzeSpectrumID(dtype);
} else if (dtype.indexOf("ASSIGNMENT") >= 0) {
this.type = Type.ASSIGNMENT;
analyzeSpectrumID(dtype);
} else {
this.type = Type.FULLSPECTRUM;
analyzeSpectrumID(dtype);
if (spectrumID == ISpectrumIdentifier.MASS && dtype.indexOf("CONTINUOUS") < 0)
this.type = Type.PEAKTABLE;
}
}
}
/**
* analyze ##DATATYPE= LDR for spectrum type.
* @param datatype java.lang.String
*/
private void analyzeSpectrumID(String dataType) {
if (dataType != null) {
dataType = dataType.toUpperCase();
if (dataType.indexOf("NMR") > -1) {
spectrumID = ISpectrumIdentifier.NMR;
} else if (dataType.indexOf("MASS") > -1) {
spectrumID = ISpectrumIdentifier.MASS;
} else if (dataType.indexOf("INFRARED") > -1) {
spectrumID = ISpectrumIdentifier.IR;
} else if (dataType.indexOf("IR") > -1) {
spectrumID = ISpectrumIdentifier.IR;
} else if (dataType.indexOf("UV") > -1) {
spectrumID = ISpectrumIdentifier.UV;
} else if (dataType.indexOf("ULTRAVIOLET") > -1) {
spectrumID = ISpectrumIdentifier.UV;
} else if (dataType.indexOf("RAMAN") > -1) {
spectrumID = ISpectrumIdentifier.RAMAN;
} else if (dataType.indexOf("FLUORESCENCE") > -1) {
spectrumID = ISpectrumIdentifier.FLUORESCENCE;
} else if (dataType.indexOf("CHROMATOGRAM") > -1) {
spectrumID = ISpectrumIdentifier.CHROMATOGRAM;
}
}
}
/**
* gets block as a simple JCAMP string
* @return java.lang.String
*/
public String asSimpleJCAMP() {
return this.data;
}
/**
* change a data record to a new value and return modified JCAMPBlock.
*
* @return JCAMPBlock modified block
* @param key java.lang.String normalized key
* @param newValue JCAMPDataRecord new data record value
*/
public JCAMPBlock changeDataRecord(String key, String newValue) throws JCAMPException {
JCAMPDataRecord oldLDR = getDataRecord(key);
if (oldLDR == null) {
errorHandler.error("LDR \"##" + key + "=\" not found in block");
return new JCAMPBlock(this.getJCAMP());
}
StringBuilder newJCAMP = new StringBuilder();
if (oldLDR.getStart() > 0) {
newJCAMP.append(this.jcamp.substring(0, oldLDR.getStart() - 1));
if (newJCAMP.charAt(newJCAMP.length() - 1) != '\n')
newJCAMP.append(CRLF);
}
newJCAMP.append("##").append(key).append("=").append(newValue);
if (newJCAMP.charAt(newJCAMP.length() - 1) != '\n')
newJCAMP.append(CRLF);
if (oldLDR.getEnd() < this.jcamp.length() - 1)
newJCAMP.append(this.jcamp.substring(oldLDR.getEnd() + 1));
return new JCAMPBlock(newJCAMP.toString());
}
/**
* get all data records, including records with duplicate key.
*
* @return com.labcontrol.jcamp.reader.JCAMPDataRecord[]
*/
public JCAMPDataRecord[] getAllDataRecords() {
return ldrs;
}
/**
* gets current ASDF decoder.
*
* @return com.creon.chem.jcamp.ASDFDecoder
*/
public ASDFDecoder getASDFDecoder() {
return asdfDecoder;
}
/**
* gets block by block ID.
* @return JCAMPBlock
* @param id int
*/
public JCAMPBlock getBlock(int id) {
return (JCAMPBlock) this.childBlocks.get(new Integer(id));
}
/**
* gets blocks within block.
* @return java.util.Enumeration
*/
public Enumeration getBlocks() {
return this.childBlocks.elements();
}
/**
* get data record by index within block (counting all duplicates).
*
* @return JCAMPDataRecord
* @param index int
*/
public JCAMPDataRecord getDataRecord(int index) {
return ldrs[index];
}
/**
* get data records by normalized key
* @return JCAMPDataRecord
* @param key java.lang.String
*/
public JCAMPDataRecord getDataRecord(String key) {
return (JCAMPDataRecord) dataRecords.get(key);
}
/**
* gets LDRs for block.
* @return java.util.Enumeration
*/
public Enumeration getDataRecords() {
return this.dataRecords.elements();
}
/**
* Insert the method's description here.
*
* @return com.creon.chem.jcamp.IErrorHandler
*/
public IErrorHandler getErrorHandler() {
return errorHandler;
}
/**
* gets block ID.
* @return int
*/
public int getID() {
JCAMPDataRecord ldr = (JCAMPDataRecord) this.dataRecords.get("BLOCKID");
if (ldr == null)
return -1;
String blockID = ldr.getValue();
String id = Utils.removeComments(blockID).trim();
return Integer.parseInt(id);
}
/**
* gets JCAMP string containing block.
*
* @return java.lang.String
*/
public String getJCAMP() {
return this.jcamp;
}
/**
* get ntuple of block.
*
* @return com.labcontrol.jcamp.reader.JCAMPNTuple
*/
public JCAMPNTuple getNTuple() {
return this.ntuple;
}
/**
* gets crossreferences, works only with SpecInfo convention!
* @return JCAMPBlock[]
*/
public JCAMPBlock[] getReferences() {
if (this.references == null) {
Vector refs = new Vector();
if (this.parent == null) {
this.references = new JCAMPBlock[0];
return this.references;
}
JCAMPDataRecord xrefLDR = getDataRecord("CROSSREFERENCE");
if (xrefLDR == null) {
this.references = new JCAMPBlock[0];
return this.references;
}
String xref = xrefLDR.getValue();
xref = Utils.removeComments(xref).trim();
StringTokenizer commaTokenizer = new StringTokenizer(xref, ",");
while (commaTokenizer.hasMoreTokens()) {
String token = commaTokenizer.nextToken().trim();
try {
int ref = Integer.parseInt(token);
JCAMPBlock linkBlock = this.parent.getBlock(ref);
refs.addElement(linkBlock);
} catch (NumberFormatException e) {
}
}
this.references = new JCAMPBlock[refs.size()];
for (int i = 0; i < refs.size(); i++) {
this.references[i] = (JCAMPBlock) refs.elementAt(i);
}
}
return this.references;
}
/**
* gets spectrum identifier.
* @return int
*/
public int getSpectrumID() {
return spectrumID;
}
/**
* gets block type.
* @return JCAMPBlock.Type
*/
public Type getType() {
return this.type;
}
/**
* gets the variable for symbol symbol.
* @param String symbol
* @return com.creon.chem.jcamp.JCAMPVariable
*/
public JCAMPVariable getVariable(String symbol) {
if (isNTupleBlock())
return ntuple.getVariable(symbol);
else {
symbol = symbol.toUpperCase();
for (int i = 0; i < vars.length; i++) {
if (symbol.equals(vars[i].getSymbol()))
return vars[i];
}
return null;
}
}
/**
* gets the variable array
*
* @return com.creon.chem.jcamp.JCAMPVariable[]
*/
public JCAMPVariable[] getVariables() {
if (isNTupleBlock())
return ntuple.getVariables();
else
return vars;
}
/**
* find child blocks within start
and end
of jcamp
string.
* collects remaining labels in string data
*/
private void initBlocks() throws JCAMPException {
int id = 0;
StringBuilder tmp = new StringBuilder();
BlockIterator blockIter = new BlockIterator(jcamp.substring(this.start, this.end));
int o0 = start;
int o1;
while (blockIter.hasNext()) {
int offset = blockIter.getOffset();
o1 = this.start + offset - 1;
tmp.append(jcamp.substring(o0, o1));
String block = blockIter.next();
o0 = this.start + offset + block.length();
o1++;
JCAMPBlock jcampBlock = new JCAMPBlock(this, jcamp, o1, o0);
int blockID = jcampBlock.getID();
if (blockID < 0) {
id--;
} else
id = blockID;
childBlocks.put(new Integer(id), jcampBlock);
}
tmp.append(jcamp.substring(o0, this.end));
this.data = tmp.toString();
}
/**
* iterator over all data records and store them into the hashtable dataRecords
*/
private void initLDRs() {
IStringIterator ldrIter = new LDRIterator(data);
int blockIndex = 0;
ArrayList tmp = new ArrayList();
while (ldrIter.hasNext()) {
int offset = ldrIter.getOffset();
String ldr = ldrIter.next();
JCAMPDataRecord dataRecord = new JCAMPDataRecord(this.data, offset, offset + ldr.length(), blockIndex);
JCAMPDataRecord ldrList = (JCAMPDataRecord) this.dataRecords.get(dataRecord.getKey());
if (ldrList == null) {
this.dataRecords.put(dataRecord.getKey(), dataRecord);
} else {
ldrList.listIterator().add(dataRecord);
}
tmp.add(dataRecord);
blockIndex++;
}
this.numDataRecords = blockIndex;
this.ldrs = new JCAMPDataRecord[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
this.ldrs[i] = (JCAMPDataRecord) tmp.get(i);
}
/**
* initialize JCAMPNTuplePages.
* TODO: handle multiple NTUPLES blocks?
*/
private void initNTuple() throws JCAMPException {
if (isStructureBlock())
return;
JCAMPDataRecord startNTupleLDR = getDataRecord("NTUPLES");
if (startNTupleLDR == null) {
this.ntupleBlock = false;
// make some safety checks
if (getDataRecord("SYMBOL") != null) {
// assume NTUPLE block, but treat as error
this.ntupleBlock = true;
errorHandler.error("missing ##NTUPLES=");
}
if (getDataRecord("VARDIM") != null) {
// assume NTUPLE block, but treat as error
this.ntupleBlock = true;
errorHandler.error("missing ##NTUPLES=");
}
if (!this.ntupleBlock)
return;
}
JCAMPDataRecord endNTupleLDR = getDataRecord("ENDNTUPLES");
if (endNTupleLDR == null) {
errorHandler.error("missing ##END NTUPLES=");
}
this.ntuple = new JCAMPNTuple(this, startNTupleLDR, endNTupleLDR);
this.ntupleBlock = true;
}
/**
* Parses the string as double.
*
* @param s the string to parse
* @return the parsed double
*/
private Double parseDouble(String s) {
try {
return new Double(s);
}
catch (NumberFormatException e) {
return new Double(s.replace(",", "."));
}
}
/**
* find definitions for all variables.
*
* @exception com.creon.chem.jcamp.JCAMPException parsing errors.
*/
private void initVariables() throws JCAMPException {
if (isStructureBlock()) // JCAMP CS has no variables
return;
if (isNTupleBlock()) // NTUPLEs are already initialized
return;
if (isLinkBlock())
return;
JCAMPDataRecord dataLDR = null;
Enumeration records = getDataRecords();
while (records.hasMoreElements()) {
JCAMPDataRecord ldr = (JCAMPDataRecord) records.nextElement();
if (ldr.isData()) {
if (dataLDR != null) {
errorHandler.error("more than one data LDR in block: use compound JCAMP");
break; // use first data block encountered
} else
dataLDR = ldr;
}
}
if (dataLDR == null) {
errorHandler.fatal("missing data LDR");
}
DataVariableInfo info = new DataVariableInfo(dataLDR);
String[] symbols = info.getSymbols();
JCAMPDataRecord ldr = getDataRecord("NPOINTS");
if (ldr == null)
errorHandler.fatal("missing required label ##NPOINTS=");
int nPoints = Integer.parseInt(ldr.getContent());
vars = new JCAMPVariable[symbols.length];
for (int i = 0; i < symbols.length; i++) {
String symbol = symbols[i].toUpperCase();
JCAMPVariable v = new JCAMPVariable(symbol);
if (i > 0)
v.setType(JCAMPVariable.Type.DEPENDENT);
else
v.setType(JCAMPVariable.Type.INDEPENDENT);
if (getType().equals(Type.FULLSPECTRUM)) {
if (info.isIncremental())
v.setFormat(JCAMPVariable.Format.ASDF);
else
v.setFormat(JCAMPVariable.Format.AFFN);
} else if (getType().equals(Type.PEAKTABLE) || getType().equals(Type.ASSIGNMENT)) {
if (symbol.equals("X") || symbol.equals("Y") || symbol.equals("W"))
v.setFormat(JCAMPVariable.Format.AFFN);
else
v.setFormat(JCAMPVariable.Format.STRING);
}
v.setDimension(nPoints);
ldr = getDataRecord(symbol + "LABEL");
if (ldr != null)
v.setLabel(ldr.getContent());
ldr = getDataRecord(symbol + "UNITS");
if (ldr != null)
v.setUnit(ldr.getContent());
ldr = getDataRecord("FIRST" + symbol);
if (ldr != null)
v.setFirst(parseDouble(ldr.getContent()));
ldr = getDataRecord("LAST" + symbol);
if (ldr != null)
v.setLast(parseDouble(ldr.getContent()));
ldr = getDataRecord(symbol + "FACTOR");
if (ldr != null)
v.setFactor(parseDouble(ldr.getContent()));
ldr = getDataRecord("MIN" + symbol);
if (ldr != null)
v.setMin(parseDouble(ldr.getContent()));
ldr = getDataRecord("MAX" + symbol);
if (ldr != null)
v.setMax(parseDouble(ldr.getContent()));
vars[i] = v;
}
}
/**
* checks if block is a JCAMP link block.
*
* @return boolean
*/
public boolean isLinkBlock() {
return this.type.equals(Type.LINK);
}
/**
* indicates a block containing ntuples.
*
* @return boolean
*/
public boolean isNTupleBlock() {
return this.ntupleBlock;
}
/**
* checks if block is a JCAMP structure block.
*
* @return boolean
*/
public boolean isStructureBlock() {
return this.type.equals(Type.STRUCTURE);
}
/**
* testing.
* @param args java.lang.String[]
*/
public static void main(String[] args) {
String jcamp = null;
try {
File dxFile = new java.io.File(args[0]);
FileReader dxIn = new FileReader(dxFile);
if (dxIn != null) {
int size;
int read;
int r;
char[] data;
size = (int) dxFile.length();
read = 0;
data = new char[size];
do {
r = dxIn.read(data, read, size - read);
read += r;
} while (r > 0);
dxIn.close();
jcamp = String.valueOf(data);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
JCAMPBlock block = new JCAMPBlock(jcamp);
System.out.println("Block Data:\n" + block.data);
System.out.println("Child Blocks: " + block.childBlocks.size());
} catch (JCAMPException e) {
e.printStackTrace();
}
}
/**
* gets number of child blocks.
* @return int
*/
public int numBlocks() {
return childBlocks.size();
}
/**
* gets number of LDRs.
* @return int
*/
public int numDataRecords() {
return numDataRecords;
}
/**
* gets number of LDRs.
* @return int
*/
public int numVariables() {
return vars.length;
}
/**
* sets ASDFDecoder
*
* @param newAsdfDecoder com.creon.chem.jcamp.ASDFDecoder
*/
public void setASDFDecoder(ASDFDecoder newAsdfDecoder) {
asdfDecoder = newAsdfDecoder;
}
/**
* sets error handler.
*
* @param newErrorHandler com.creon.chem.jcamp.IErrorHandler
*/
public void setErrorHandler(IErrorHandler newErrorHandler) {
errorHandler = newErrorHandler;
}
/**
* sets spectrum identifier.
* @param newSpectrumID int
*/
public void setSpectrumID(int newSpectrumID) {
spectrumID = newSpectrumID;
}
public boolean isValidating() {
return isValidating;
}
public void setValidating(boolean useCheckValues) {
this.isValidating = useCheckValues;
this.asdfDecoder.enableValidation(useCheckValues);
}
}