/* File: StreamDescriptor.java * Copyright (C) 2002-2003 The University of Iowa * Created by: Jeremy Faden <jbf@space.physics.uiowa.edu> * Jessica Swanner <jessica@space.physics.uiowa.edu> * Edward E. West <eew@space.physics.uiowa.edu> * * This file is part of the das2 library. * * das2 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 org.das2.stream; import org.das2.DasIOException; import org.das2.datum.DatumVector; import org.das2.util.IDLParser; import java.io.*; import org.xml.sax.InputSource; import org.xml.sax.SAXException; //import org.apache.xml.serialize.OutputFormat; //import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.*; import java.nio.ByteBuffer; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer; import org.xml.sax.SAXParseException; /** Represents the global properties of the stream, that are accessible to * datasets within. * @author jbf */ public class StreamDescriptor implements SkeletonDescriptor, Cloneable { private Map properties = new HashMap(); private StreamXDescriptor xDescriptor; private ArrayList yDescriptors = new ArrayList(); private String compression; /** Creates a new instance of StreamProperties */ public StreamDescriptor(Element element) throws StreamException { if (element.getTagName().equals("stream")) { processElement(element); } else { processLegacyElement(element); } } private void processElement(Element element) throws StreamException { compression = element.getAttribute("compression"); NodeList list = element.getElementsByTagName("properties"); if (list.getLength() != 0) { Element propertiesElement = (Element)list.item(0); Map m = StreamTool.processPropertiesElement(propertiesElement); properties.putAll(m); } } private void processLegacyElement(Element element) throws StreamException { NodeList children= element.getChildNodes(); for (int i=0; i<children.getLength(); i++) { Node node= children.item(i); if ( node instanceof Element ) { Element child = (Element)node; String name= child.getTagName(); if ( name.equals("X")) { xDescriptor = new StreamXDescriptor(child); } else if ( name.equals("YScan")) { StreamYScanDescriptor d= new StreamYScanDescriptor(child); yDescriptors.add(d); } else if ( name.equals("MultiY")) { StreamScalarDescriptor d= new StreamScalarDescriptor(child); yDescriptors.add(d); } } } } public StreamDescriptor() { } public StreamXDescriptor getXDescriptor() { return xDescriptor; } public void setXDescriptor(StreamXDescriptor x) { xDescriptor = x; } public void addYScan(StreamYScanDescriptor y) { yDescriptors.add(y); } public void addYMulti(StreamScalarDescriptor y) { yDescriptors.add(y); } public List getYDescriptors() { return Collections.unmodifiableList(yDescriptors); } public Object getProperty(String name) { return properties.get(name); } public Map getProperties() { return Collections.unmodifiableMap(properties); } public void setProperty(String name, Object value) { properties.put(name, value); } public static Document parseHeader(Reader header) throws DasIOException, DasStreamFormatException { try { /* header = new FilterReader(header) { public int read() throws IOException { int result = super.read(); if (result != -1) { System.out.print((char)result); } return result; } public int read(char[] c, int offset, int length) throws IOException { int result = super.read(c, offset, length); if (result != -1) { System.out.print(new String(c, offset, result)); } return result; } }; */ DocumentBuilder builder= DocumentBuilderFactory.newInstance().newDocumentBuilder(); InputSource source = new InputSource(header); Document document= builder.parse(source); return document; } catch ( ParserConfigurationException ex ) { throw new IllegalStateException(ex.getMessage()); } catch ( SAXException ex ) { String msg; if ( ex instanceof SAXParseException ) { SAXParseException spe= (SAXParseException) ex; msg= spe.getMessage() + "at line="+spe.getLineNumber()+" col="+spe.getColumnNumber(); } else { msg= ex.getMessage(); } DasIOException thr= new DasIOException(msg); throw thr; } catch ( IOException ex) { throw new DasIOException(ex.getMessage()); } } public int getSizeBytes() { return -1; } public DatumVector read(ByteBuffer input) { return null; } public void write(DatumVector input, ByteBuffer output) { } public static StreamDescriptor createLegacyDescriptor(BufferedReader in) throws IOException { IDLParser parser = new IDLParser(); double[] array; String key; String value; int index, lineNumber; lineNumber = 1; Pattern labelPattern = Pattern.compile("\\s*label\\((\\d+)\\)\\s*"); Matcher matcher; StreamDescriptor result = new StreamDescriptor(); result.properties.put("legacy", "true"); for (String line = in.readLine(); line != null; line = in.readLine()) { //Get rid of any comments index = line.trim().indexOf(';'); if (index == 0) { lineNumber++; continue; } else if (index != -1) { line = line.substring(0, index); } //Break line into key-value pairs index = line.indexOf('='); key = line.substring(0,index).trim(); value = line.substring(index+1).trim(); //deterimine type of value if (key.equals("description")) { String description = value.substring(1, value.length()-1); result.properties.put(key, description); } else if (key.equals("groupAccess")) { result.properties.put(key, value.substring(1, value.length()-1)); } else if (key.equals("form")) { result.properties.put(key, value); } else if (key.equals("reader")) { String reader = value.substring(1, value.length()-1); result.properties.put(key, reader); } else if (key.equals("x_parameter")) { String x_parameter = value.substring(1, value.length()-1); result.properties.put(key, x_parameter); } else if (key.equals("x_unit")) { String x_unit = value.substring(1, value.length()-1); result.properties.put(key, x_unit); } else if (key.equals("y_parameter")) { String y_parameter = value.substring(1, value.length()-1); result.properties.put(key, y_parameter); } else if (key.equals("y_unit")) { String y_unit = value.substring(1, value.length()-1); result.properties.put(key, y_unit); } else if (key.equals("z_parameter")) { String z_parameter = value.substring(1, value.length()-1); result.properties.put(key, z_parameter); } else if (key.equals("z_unit")) { String z_unit = value.substring(1, value.length()-1); result.properties.put(key, z_unit); } else if (key.equals("x_sample_width")) { double x_sample_width = parser.parseIDLScalar(value); if ( Double.isNaN(x_sample_width) ) throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); result.properties.put(key, new Double(x_sample_width)); } else if (key.equals("y_fill")) { double y_fill = parser.parseIDLScalar(value); if (Double.isNaN( Double.NaN )) throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); result.properties.put(key, new Double(y_fill)); } else if (key.equals("z_fill")) { double z_fill = (float)parser.parseIDLScalar(value); if (Double.isNaN(Float.NaN)) throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); result.properties.put(key, new Float(z_fill)); } else if (key.equals("y_coordinate")) { array = parser.parseIDLArray(value); if (array == null) { throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); } result.properties.put(key, array); } else if (key.equals("ny")) { int ny; try { ny = Integer.parseInt(value); } catch (NumberFormatException nfe) { throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); } result.properties.put(key, Integer.valueOf(ny)); } else if (key.equals("items")) { int items; try { items = Integer.parseInt(value); } catch (NumberFormatException nfe) { throw new IOException("Could not parse \"" + value + "\" at line " + lineNumber); } result.properties.put(key, Integer.valueOf(items)); } else if ((matcher = labelPattern.matcher(key)).matches()) { int i = Integer.parseInt(matcher.group(1)); value = value.substring(1, value.length() - 1); if (i == 0) { result.properties.put("label", value); } else { String[] labels = ensureCapacity((String[])result.properties.get("plane-list"), i); labels[i - 1] = value; result.properties.put("plane-list", labels); result.properties.put(value + ".label", value); } } else if (value.charAt(0)=='\'' && value.charAt(value.length()-1)=='\'') { result.properties.put(key, value.substring(1, value.length()-1)); } else if (value.charAt(0)=='"' && value.charAt(value.length()-1)=='"') { result.properties.put(key, value.substring(1, value.length()-1)); } else { result.properties.put(key, value); } lineNumber++; } String[] planeList = (String[])result.properties.get("plane-list"); if (planeList != null) { result.properties.put("plane-list", Collections.unmodifiableList(Arrays.asList(planeList))); } result.properties.put("legacy", "true"); return result; } public static String createHeader(Document document) throws DasIOException { StringWriter writer= new StringWriter(); DOMImplementationLS ls = (DOMImplementationLS) document.getImplementation().getFeature("LS", "3.0"); LSOutput output = ls.createLSOutput(); output.setCharacterStream(writer); LSSerializer serializer = ls.createLSSerializer(); serializer.write(document, output); /* OutputFormat format= new OutputFormat(); format.setOmitXMLDeclaration(true); format.setEncoding("UTF-8"); XMLSerializer serializer= new XMLSerializer(writer, format); try { serializer.serialize(document); } catch ( IOException ex) { throw new DasIOException(ex.getMessage()); } */ String result= writer.toString(); return result; } /* // read off the bytes that are the xml header of the stream. protected static byte[] readHeader( InputStream in ) throws IOException { byte[] buffer= new byte[10000]; int b; b= in.read(); if ( b==(int)'[' ) { // [00] for ( int i=0; i<3; i++ ) b= in.read(); } return StreamTool.readXML( in ); } */ private static String[] ensureCapacity(String[] array, int capacity) { if (array == null) { return new String[capacity]; } else if (array.length >= capacity) { return array; } else { String[] temp = new String[capacity]; System.arraycopy(array, 0, temp, 0, array.length); return temp; } } /** Getter for property compression. * @return Value of property compression. * */ public String getCompression() { return compression; } /** Setter for property compression. * @param compression New value of property compression. * */ public void setCompression(String compression) { this.compression = compression; } public Element getDOMElement(Document document) { Element element = document.createElement("stream"); if (compression != null && !compression.equals("")) { element.setAttribute("compression", compression); } if (!properties.isEmpty()) { Element propertiesElement = StreamTool.processPropertiesMap( document, properties ); element.appendChild(propertiesElement); } return element; } public Object clone() { try { StreamDescriptor clone = (StreamDescriptor)super.clone(); clone.properties = new HashMap(this.properties); return clone; } catch (CloneNotSupportedException cnse) { throw new RuntimeException(cnse); } } @Override public String toString() { return "StreamDescriptor " + this.properties.size() + " properties"; } }