All Downloads are FREE. Search and download functionalities are using the official Maven repository.

decodes.datasource.EdlPMParser Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
/*
*  $Id$
*
*  $Log$
*  Revision 1.3  2015/02/06 19:04:39  mmaloney
*  POLL STOP should set message time.
*
*  Revision 1.2  2015/01/06 16:09:31  mmaloney
*  First cut of Polling Modules
*
*  Revision 1.1.1.1  2014/05/19 15:28:59  mmaloney
*  OPENDCS 6.0 Initial Checkin
*
*  Revision 1.8  2012/09/06 19:03:25  shweta
*  fixed bug now when Xlinks have seconds embedded in header time.
*
*  Revision 1.7  2012/08/10 18:44:12  shweta
*  Parse Xlink header for GPRSLinks
*
*  Revision 1.6  2012/06/25 19:35:29  shweta
*  reverted back last change
*
*  Revision 1.4  2011/07/14 19:49:35  shweta
*  removed converting station name to uppercase.
*
*  Revision 1.3  2010/04/14 19:58:02  mjmaloney
*  Set GOES ID to Medium ID (kludge)
*
*  Revision 1.2  2009/10/25 15:37:40  mjmaloney
*  SSP Implementation
*
*  Revision 1.1  2008/04/04 18:21:00  cvs
*  Added legacy code to repository
*
*  Revision 1.5  2006/08/31 20:43:12  mmaloney
*  dev
*
*  Revision 1.4  2006/08/31 20:42:23  mmaloney
*  Added debug.
*
*  Revision 1.3  2004/08/24 23:52:43  mjmaloney
*  Added javadocs.
*
*  Revision 1.2  2003/12/12 17:55:32  mjmaloney
*  Working implementation of DirectoryDataSource.
*
*  Revision 1.1  2003/12/07 20:36:47  mjmaloney
*  First working implementation of EDL time stamping.
*
*/
package decodes.datasource;

import java.util.Date;
import java.util.HashMap;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
import java.text.ParseException;

import ilex.var.Variable;
import ilex.util.Logger;
import decodes.datasource.RawMessage;
import decodes.db.Constants;

/**
Performance Measurement Parser for USGS EDL Header Lines.
*/
public class EdlPMParser extends PMParser
{
	// Private time/date stamp parsers:
	private static SimpleDateFormat beginDateTimeSdf = 
		new SimpleDateFormat("yyyyMMddHHmm Z");
	
	// Private time/date stamp parsers:
		private static SimpleDateFormat xlinkDateTimeSdf = 
			new SimpleDateFormat("yyyyMMddHHmmss Z");
	
	private static SimpleDateFormat endTimeSdf =
		new SimpleDateFormat("yyMMdd HHmmss Z");
	
	// The following properties can be set by this parser.

	/**  The STATION ID parsed out of the neader. */
	public static final String STATION = "Station";

	/** The length of the message that follows the header. */
	public static final String MESSAGE_LENGTH = GoesPMParser.MESSAGE_LENGTH;

	/**
	  The end time of the message. Set from DEVICE END TIME. Possibly 
	  over-ridden by ACTUAL END TIME. Stored as a Date Variable.
	*/
	public static final String MESSAGE_TIME = GoesPMParser.MESSAGE_TIME;

	/** Device End Time, stored as a string. */
	public static final String DEVICE_END_TIME = "DeviceEndTime";

	/** Actual End Time, stored as a string. */
	public static final String ACTUAL_END_TIME = "ActualEndTime";

	/**
	  Optional start time, complete time stamp stored as a date.
	  This is set from the BEGIN TIME and BEGIN DATE header fields.
	*/
	public static final String BEGIN_TIME_STAMP = "BeginTimeStamp";

	public static final String END_TIME_STAMP = "EndTimeStamp";

	/** The DEVICE string contained in the header */
	public static final String DEVICE = "Device";

	/** The SOURCE string contained in the header */
	public static final String SOURCE = "Source";

	/** A string containing the multi-line optional EDL NOTES field. */
	public static final String EDL_NOTES = "EdlNotes";

	/** Flag set when header is parsed, indicating whether begin time had TZ. */
	public boolean beginTimeHasTz;
	
	/** Flag set when header is parsed, indicating whether xlink time had TZ. */
	public boolean XLinkTimeHasTz;
	
	/** Flag set when header is parsed, indicating if time is in format HHmmss */
	public boolean XLinkTimeHasSecs=false;
	
	public static final String POLL_START = "PollStart";
	public static final String POLL_STOP = "PollStop";


	/** Use factory method in PMParser, do not construct directly. */
	public EdlPMParser()
	{
		super();
	}

	/** Returns the constant string "data-logger". */
	public String getHeaderType() { return "data-logger"; }

	/** Returns constant medium type for platform association. */
	public String getMediumType() { return Constants.medium_EDL; }

	/**
	  Parses performance measurements from raw message and populates
	  a hashmap (string - Variable) table of results.
	  Also sets the boolean 'beginTimeHasTz' indicating whether or not the
	  BEGIN TIME stamp (if one was present) had a time zone indicator. If
	  it does NOT, then you should adjust the begin time by the site's TZ.
	  @param msg the raw message to parse
	*/
	public void parsePerformanceMeasurements(RawMessage msg) throws HeaderParseException
	{
		beginTimeHasTz = false;
		byte data[] = msg.getData();
		int len = data.length;

		boolean inNotes = false;
		String beginDate = null;
		String beginTime = null;
		String endTime = null;
		String station = null;
		String device = null;
		String xLinkDate = null;
		String xLinkTime = null;
		StringBuffer notes = new StringBuffer();
		int e = 0;
		for (int p = 0; p < len - 3; p = e)
		{
			// Find the beginning of the next line.
			for (e = p; e < len && data[e] != (byte) '\n'; e++)
				;
			e++;

			// Check for start of new tag.
			if (data[p] == (byte) '/' && data[p + 1] == (byte) '/')
			{
				p += 2;

				String s = new String(data, p, e - p);

				// Removed uppercase as in case of dataloggers if transport
				// medium is defined in lowercase,
				// decodes fails to find matching platform

				// s = s.toUpperCase().trim();

				s = s.trim();
				if (s.length() == 0)
					continue; // Skip comment line with just '//'
				if (s.startsWith("STATION"))
				{
					String val = s.substring(7).trim();
					msg.setPM(STATION, new Variable(val));
				}
				else if (s.startsWith("DEVICE END TIME")) // do before DEVICE !!
				{
					if (endTime == null)
						endTime = s.substring(15).trim();
				}
				else if (s.startsWith("DEVICE"))
				{
					String val = s.substring(6).trim();
					int hyphen = val.indexOf('-');
					int space = val.indexOf(' ');
					if (hyphen >= 0)
					{
						if (space > 0 && hyphen < space)
							val = val.substring(0, space);
						else if (space > 0 && space < hyphen)
							val = val.substring(0, space) + "-" + val.substring(space + 1);
					}
					else
					// no hyphen
					{
						if (space >= 0)
							val = val.substring(0, space) + "-" + val.substring(space + 1);
					}
					space = val.indexOf(' ');
					if (space > 0)
						val = val.substring(0, space);
					msg.setPM(DEVICE, new Variable(val));
				}
				else if (s.startsWith("SOURCE"))
				{
					String val = s.substring(6).trim();
					msg.setPM(SOURCE, new Variable(val));
				}
				else if (s.startsWith("BEGIN DATE"))
				{
					beginDate = s.substring(10).trim();
				}
				else if (s.startsWith("BEGIN TIME"))
				{
					beginTime = s.substring(10).trim();
				}
				else if (s.startsWith("XLINK DATE"))
				{
					xLinkDate = s.substring(10).trim();
				}
				else if (s.startsWith("XLINK TIME"))
				{
					xLinkTime = s.substring(10).trim();
				}
				else if (s.startsWith("ACTUAL END TIME"))
				{
					endTime = s.substring(15).trim();
				}
				else if (s.startsWith("EDL NOTES") || s.startsWith("PFC NOTES")
					|| s.startsWith("DEVICE NOTES"))
				{
					inNotes = true;
				}
				else if (s.startsWith("DATA"))
				{
					inNotes = false;
				}
				else if (s.startsWith("POLL START"))
				{
					try
					{
						Date d = endTimeSdf.parse(s.substring(10).trim());
						msg.setPM(POLL_START, new Variable(d));
					}
					catch (Exception ex)
					{
						Logger.instance().log(Logger.E_FAILURE,
							"Unparsable POLL START '" + beginTime + "': Ignored.");
					}
				}
				else if (s.startsWith("POLL STOP"))
				{
					try
					{
						Date d = endTimeSdf.parse(s.substring(9).trim());
						msg.setPM(POLL_STOP, new Variable(d));
						msg.setTimeStamp(d);
					}
					catch (Exception ex)
					{
						Logger.instance().log(Logger.E_FAILURE,
							"Unparsable POLL STOP '" + beginTime + "': Ignored.");
					}
				}
			}
			else if (inNotes)
				notes.append(new String(data, p, e - p));
			else
			// this is the end of the header!
			{
				msg.setHeaderLength(p);
				msg.setPM(MESSAGE_LENGTH, new Variable((long) (len - p)));
				break;
			}
		}

		if (beginDate != null)
		{
			if (beginTime != null)
			{
				// begin time can optionally contain time zone.
				int idx = beginTime.lastIndexOf('S');
				if (idx != -1)
				{
					beginTimeHasTz = true;
					beginTime = beginTime.substring(0, idx) + "00";
				}
				else
				// Add dummy offset to UTC
				{
					beginTimeHasTz = false;
					beginTime += " +0000";
				}
				beginDate += beginTime;
			}
			else
				beginDate += "0000 +0000"; // HHMM & TZ
			try
			{
				Logger.instance().debug1("Parsing begin date/time '" + beginDate + "'");
				Date d = beginDateTimeSdf.parse(beginDate);
				msg.setPM(BEGIN_TIME_STAMP, new Variable(d));
			}
			catch (ParseException ex)
			{
				Logger.instance()
					.log(Logger.E_FAILURE, "Unparsable begin time '" + beginTime + "': Ignored.");
			}
		}

		if (endTime != null)
		{
			// Check for start of timezone.
			int idx = endTime.indexOf('-');
			if (idx == -1)
				idx = endTime.indexOf('+');

			if (idx == -1) // No time zone at all, add one.
				endTime += " +0000";
			else
			{
				int i = ++idx; // idx points to first digit after sign.

				for (; i < endTime.length() && i - idx <= 4 && Character.isDigit(endTime.charAt(i)); i++)
					;
				// i now points to first non-digit after TZ

				switch (i - idx)
				// i-idx is # of digits after sign.
				{
				case 0:
					endTime = endTime.substring(0, idx) + "0000";
					break;
				case 1: // 1 digit hour? move to position 2 in HHMM:
					endTime = endTime.substring(0, idx) + "0" + endTime.charAt(idx) + "00";
					break;
				case 2: // HH only, add MM
					endTime = endTime.substring(0, i) + "00";
					break;
				case 3: // HHM, ad lcd
					endTime = endTime.substring(0, i) + "0";
					break;
				default: // complete. Just truncate at 4 digits.
					endTime = endTime.substring(0, idx + 4);
				}
			}

			try
			{
				msg.setPM(END_TIME_STAMP, new Variable(endTimeSdf.parse(endTime)));
			}
			catch (Exception ex)
			{
				Logger.instance().log(Logger.E_FAILURE, "Unparsable end time '" + endTime + "': Ignored.");
			}
		}

		if (xLinkDate != null)
		{
			if (xLinkTime != null)
			{

				if (xLinkTime.length() == 10)
					XLinkTimeHasSecs = true;
				else
					XLinkTimeHasSecs = false;

				// begin time can optionally contain time zone.
				int idx = xLinkTime.lastIndexOf('S');
				if (idx != -1)
				{
					XLinkTimeHasTz = true;
					xLinkTime = beginTime.substring(0, idx) + "00";
				}
				else
				// Add dummy offset to UTC
				{
					XLinkTimeHasTz = false;
					xLinkTime += " +0000";
				}
				xLinkDate += xLinkTime;
			}
			else
				xLinkDate += "0000 +0000"; // HHMM & TZ
			try
			{
				Logger.instance().debug1("Parsing xLink date/time '" + xLinkDate + "'");

				if (XLinkTimeHasSecs)
				{
					Date dd = xlinkDateTimeSdf.parse(xLinkDate);
					msg.setPM(GoesPMParser.MESSAGE_TIME, new Variable(dd));
					msg.setTimeStamp(dd);
				}
				else
				{
					Date d = beginDateTimeSdf.parse(xLinkDate);
					msg.setPM(GoesPMParser.MESSAGE_TIME, new Variable(d));
					msg.setTimeStamp(d);
				}
			}
			catch (ParseException ex)
			{
				Logger.instance()
					.log(Logger.E_FAILURE, "Unparsable xlink time '" + xLinkTime + "': Ignored.");
			}
		}

		if (notes.length() > 0)
		{
			msg.setPM(EDL_NOTES, new Variable(notes.toString()));
		}

		// Construct medium ID by concatenating station to device.
		if (msg.getMediumId() == null)
		{
			String mid = System.getProperty("MEDIUMID");
			if (mid == null)
			{
				Variable v = msg.getPM(STATION);
				if (v == null)
					throw new HeaderParseException("No STATION in EDL file.");
				mid = v.getStringValue();
				v = msg.getPM(DEVICE);
				if (v != null)
					mid = mid + "-" + v.getStringValue();
			}
			Logger.instance().log(Logger.E_DEBUG3, "Setting EDL File Medium ID to '" + mid + "'");
			msg.setMediumId(mid);
			msg.setPM(GoesPMParser.DCP_ADDRESS, new Variable(mid));
		}
	}

	/**
	  @return -1 because Header length is variable, not fixed.
	*/
	public int getHeaderLength()
	{
		return -1;
	}


	/**
	  @return false, the header contains no indication of the message length.
	*/
	public boolean containsExplicitLength()
	{
		return false;
	}
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy