//
// ReadWxText.java
//

/*
This source file is part of the edu.wisc.ssec.mcidas package and is
Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink,
Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden
and others.
 
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package edu.wisc.ssec.mcidas.adde;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.lang.*;
import java.util.*;
import edu.wisc.ssec.mcidas.McIDASUtil;

/** 
 * Read text from an ADDE server interface for McIDAS ADDE data sets.  
 * This class handles file, weather text and obs text requests.
 * 

*

 * For File Reading:
 *   URLs must all have the following format   
 *     adde://host/text?file=filename.ext
 *
 *   there can be any valid combination of the following supported keywords:
 *
 *     file - name of text file on ADDE server
 *
 *   the following keywords are required:
 *
 *     file
 *
 *   an example URL might look like:
 *     adde://viper/text?file=filename.ext
 *
 * For Weather Text Reading:
 *   URLs must all have the following format   
 *     adde://host/wxtext?group=group&key1=value1&key2=val2....&keyn=valn
 *
 *   there can be any valid combination of the following supported keywords:
 *
 *     group=<group>         weather text group (default= RTWXTEXT)
 *     prod=<product>        predefind product name
 *     apro=<val1 .. valn>   AFOS/AWIPS product headers to match (don't 
 *                           use with wmo keyword
 *     astn=<val1 .. valn>   AFOS/AWIPS stations to match
 *     wmo= <val1 .. valn>   WMO product headers to match (don't 
 *                           use with apro keyword
 *     wstn=<val1 .. valn>   WMO stations to match
 *     day=<start end>       range of days to search
 *     dtime=<numhours>      maximum number of hours to search back (def=96)
 *     match=<match strings> list of character match strings to find from text
 *     num=<num>             number of matches to find (def=1)
 *
 *   the following keywords are required:
 *
 *     day  (bug causes it not to default to current day)
 *     one of the selection criteria
 *
 *   an example URL might look like:
 *     adde://adde.ucar.edu/wxtext?group=rtwxtext&prod=zone_fcst&astn=bou
 *
 * For Observational Text Reading:
 *   URLs must all have the following format   
 *     adde://host/obtext?group=group&descr=descr&key1=value1....&keyn=valn
 *
 *   there can be any valid combination of the following supported keywords:
 *
 *     group=<group>         weather text group (default= RTWXTEXT)
 *     descr=<descriptor>    weather text subgroup (default=SFCHOURLY)
 *     id=<id1 id2 ... idn>  list of station ids
 *     co=<co1 co2 ... con>  list of countries
 *     reg=<reg1 reg2..regn> list of regions
 *     newest=<day hour>     most recent time to allow in request 
 *                           (def=current time)
 *     oldest=<day hour>     oldest observation time to allow in request
 *     type=<type>           numeric value for the type of ob
 *     nhours=<numhours>     maximum number of hours to search
 *     num=<num>             number of matches to find (def=1)
 *
 *   the following keywords are required:
 *
 *     group
 *     descr
 *     id, co, or reg
 *
 *   an example URL might look like:
 *     adde://adde.ucar.edu/obtext?group=rtwxtext&descr=sfchourly&id=kden&num=2
 *
 * 
* * @author Tom Whittaker/Don Murray * */ public class AddeTextReader { // load protocol for ADDE URLs // See java.net.URL for explanation of URL handling static { try { String handlers = System.getProperty("java.protocol.handler.pkgs"); String newProperty = null; if (handlers == null) newProperty = "edu.wisc.ssec.mcidas"; else if (handlers.indexOf("edu.wisc.ssec.mcidas") < 0) newProperty = "edu.wisc.ssec.mcidas | " + handlers; if (newProperty != null) // was set above System.setProperty("java.protocol.handler.pkgs", newProperty); } catch (Exception e) { System.out.println( "Unable to set System Property: java.protocol.handler.pkgs"); } } private int status=0; // read status private String statusString = "OK"; private boolean debug = false; // debug private Vector linesOfText = null; private URLConnection urlc; private DataInputStream dis; private final int HEARTBEAT = 11223344; private List wxTextProds = new ArrayList(); /** * Creates an AddeTextReader object that allows reading an ADDE * text file or weather text * * @param request ADDE URL to read from. See class javadoc. */ public AddeTextReader(String request) { try { URL url = new URL(request); debug = request.indexOf("debug=true") > 0; if (debug) System.out.println("Request: "+request); urlc = url.openConnection(); InputStream is = urlc.getInputStream(); dis = new DataInputStream(is); } catch (AddeURLException ae) { status = -1; statusString = "No data found"; String aes = ae.toString(); if (aes.indexOf(" Accounting ") != -1) { statusString = "No accounting data"; status = -3; } if (debug) System.out.println("AddeTextReader Exception:"+aes); } catch (Exception e) { status = -2; if (debug) System.out.println("AddeTextReader Exception:"+e); statusString = "Error opening connection: "+e; } linesOfText = new Vector(); if (status == 0) readText(((AddeURLConnection) urlc).getRequestType()); if (linesOfText.size() < 1) statusString = "No data read"; status = linesOfText.size(); } private void readText(int reqType) { switch(reqType) { case AddeURLConnection.TXTG: readTextFile(); break; case AddeURLConnection.WTXG: readWxText(); break; case AddeURLConnection.OBTG: readObText(); break; } } private void readTextFile() { int numBytes; try { numBytes = ((AddeURLConnection) urlc).getInitialRecordSize(); if (debug) System.out.println("ReadTextFile: initial numBytes = " + numBytes); numBytes = dis.readInt(); while ((numBytes = dis.readInt()) != 0) { if (debug) System.out.println("ReadTextFile: numBytes = " + numBytes); byte[] data = new byte[numBytes]; dis.readFully(data,0,numBytes); String s = new String(data); if (debug) System.out.println(s); linesOfText.addElement(s); } } catch (Exception iox) { statusString = " "+iox; } } private void readWxText() { int numBytes; /* From the McIDAS programmer's ref: The server sends the client the following information: o 4-byte value containing the length of the client request string; this lets users know how their request was expanded when the PROD keyword is specified the expanded client request string o heartbeat value if needed o 4-byte value containing the total number of bytes of data for this text block, including the 64-byte header and the text 64-byte text header o n bytes of 80-character text, blank padded The last three pieces of information are repeated until no more data is found. */ try { numBytes = ((AddeURLConnection) urlc).getInitialRecordSize(); if (debug) System.out.println("ReadWxText: initial numBytes = " + numBytes); // Read in the expanded client request string byte[] expandedRequest = new byte[numBytes]; dis.readFully(expandedRequest,0,numBytes); String s = new String(expandedRequest); if (debug) System.out.println("Server interpreted request as:\n " + s); // look for heartbeat while ((numBytes = dis.readInt()) == 4) { int check = dis.readInt(); if (check != HEARTBEAT) { // must be number of bytes to read numBytes = check; break; } } // Now we go read the data if (debug) System.out.println("numBytes for text = "+numBytes); wxTextProds = new ArrayList(); while (numBytes != 0) { // read in the header byte[] header = new byte[64]; dis.readFully(header,0,64); WxTextProduct wtp = new WxTextProduct(header); String head = new String(header); // note this is not true text so prints as garbage //if (debug) System.out.println(decodeWxTextHeader(header)); if (debug) System.out.println(wtp); // read in the text in 80 byte chunks byte[] text = new byte[numBytes-64]; dis.readFully(text,0,numBytes-64); int nLines = text.length/80; if (debug) System.out.println("nLines = " + nLines); StringBuilder wxText = new StringBuilder(); for (int i = 0; i < nLines; i++) { String line = new String(text, i*80, 80); linesOfText.add(line); wxText.append(line); wxText.append("\n"); } wtp.setText(wxText.toString()); wxTextProds.add(wtp); // read in next length, but check for heartbeat while ((numBytes = dis.readInt()) == 4) { int check = dis.readInt(); if (check != HEARTBEAT) { // must be number of bytes to read numBytes = check; break; } } } } catch (Exception iox) { statusString = " "+iox; } } private void readObText() { int numBytes; /* From the McIDAS programmer's ref: Once the data is formatted, the text data can be sent to the client. The server sends the client the following information: o 4-byte value containing the length of the text header, which is currently 96; when all the data is sent, this value is reset to zero o 96-byte text header o 4-byte value containing the number of bytes of text to be sent o n bytes of text; 80 characters per line, blank padded This information should be repeated until no more data is found. */ try { numBytes = ((AddeURLConnection) urlc).getInitialRecordSize(); if (debug) System.out.println("ReadObText: initial numBytes = " + numBytes); while( numBytes != 0) { // Read in the header byte[] header = new byte[numBytes]; dis.readFully(header,0,numBytes); String s = new String(header); if (debug) System.out.println(decodeObsHeader(header)); numBytes = dis.readInt(); // Now we go read the data if (debug) System.out.println("numBytes for text = "+numBytes); // read in the data byte[] text = new byte[numBytes]; dis.readFully(text,0,numBytes); int nLines = text.length/80; if (debug) System.out.println("nLines = " + nLines); for (int i = 0; i < nLines; i++) { String line = new String(text, i*80, 80); linesOfText.add(line); } numBytes = dis.readInt(); } } catch (Exception iox) { statusString = " "+iox; } } /** * Get a string representation of the status code * @return human readable status */ public String getStatus() { return statusString; } /** * Return the status code of the read * @return status code (>0 == read okay); */ public int getStatusCode() { return status; } /** * Return the number of lines of text that were read. * @return number of lines. */ public int getNumLines() { return linesOfText.size(); } /** * Return the text read from the server. If there was a problem * the error message is returned. * @return text from server or error message */ public String getText() { StringBuffer buf = new StringBuffer(); if (getStatusCode() <= 0) { buf.append(getStatus()); } else { for (Iterator iter = linesOfText.iterator(); iter.hasNext();) { buf.append((String) iter.next()); buf.append("\n"); } } return buf.toString(); } public Vector getLinesOfText() { Vector v = new Vector(); if (getStatusCode() <= 0) { v.add(getStatus()); } else { v.addAll(linesOfText); } return v; } public List getWxTextProducts() { List retList = new ArrayList(); retList.addAll(wxTextProds); return retList; } /** test by running 'java edu.wisc.ssec.mcidas.adde.AddeTextReader' */ public static void main (String[] args) throws Exception { String request = (args.length == 0) ? "adde://adde.ucar.edu/text?file=PUBLIC.SRV" : args[0]; AddeTextReader atr = new AddeTextReader(request); String status = atr.getStatus(); System.out.println("\n" + atr.getText()); } private String decodeObsHeader(byte[] header) { StringBuffer buf = new StringBuffer(); int[] values = McIDASUtil.bytesToIntegerArray(header,0,13); buf.append("Ver = "); buf.append(values[0]); buf.append(" ObType = "); buf.append(values[1]); buf.append(" ActFlag = "); buf.append(values[2]); buf.append(" IDType = "); buf.append(values[9]); buf.append("\nStarting at "); buf.append(values[3]); buf.append(" "); buf.append(values[4]); buf.append(" "); buf.append(values[5]); buf.append("\nEnding at "); buf.append(values[6]); buf.append(" "); buf.append(values[7]); buf.append(" "); buf.append(values[8]); return buf.toString(); } private String decodeWxTextHeader(byte[] header) { StringBuffer buf = new StringBuffer(); int[] values = McIDASUtil.bytesToIntegerArray(header,0,13); buf.append("SOU nb location day time WMO WSTN APRO ASTN\n"); buf.append("--- ---- -------- ------- ------ ------- ---- ---- ----\n"); buf.append(McIDASUtil.intBitsToString(values[0])); buf.append(values[1]); buf.append(" "); buf.append(values[2]); buf.append(" "); buf.append(values[10]); buf.append(" "); buf.append(values[3]); buf.append(" "); buf.append(McIDASUtil.intBitsToString(values[4])); buf.append(values[5]); buf.append(" "); buf.append(McIDASUtil.intBitsToString(values[6])); buf.append(" "); buf.append(McIDASUtil.intBitsToString(values[7])); buf.append(" "); buf.append(McIDASUtil.intBitsToString(values[8])); return buf.toString(); } }

Ads help maintain this website.