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

lrgs.ddsserver.MessageArchiveRetriever 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$
*
*  This is open-source software written by ILEX Engineering, Inc., under
*  contract to the federal government. You are free to copy and use this
*  source code for your own purposes, except that no part of this source
*  code may be claimed to be proprietary.
*
*  Except for specific contractual terms between ILEX and the federal 
*  government, this source code is provided completely without warranty.
*  For more information contact: [email protected]
*/
package lrgs.ddsserver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import ilex.util.IDateFormat;
import ilex.util.Logger;
import lrgs.apistatus.AttachedProcess;
import lrgs.common.ArchiveUnavailableException;
import lrgs.common.SearchSyntaxException;
import lrgs.common.SearchTimeoutException;
import lrgs.common.UntilReachedException;
import lrgs.common.EndOfArchiveException;
import lrgs.common.DcpMsgRetriever;
import lrgs.common.DcpMsgFlag;
import lrgs.common.DcpMsgIndex;
import lrgs.common.DcpMsg;
import lrgs.common.DcpAddress;
import lrgs.common.DcpNameMapper;
import lrgs.common.DcpMsgSource;
import lrgs.common.LrgsErrorCode;
import lrgs.common.SearchCriteria;
import lrgs.archive.MsgArchive;
import lrgs.archive.MsgFilter;
import lrgs.archive.SearchHandle;

/**
This class acts both as the retriever and the source for the new Java-Only-
Archive.
*/
public class MessageArchiveRetriever 
	extends DcpMsgRetriever 
	implements MsgFilter, DcpMsgSource
{
	private SearchHandle searchHandle;

	/** LrgsSince or null if none specified. */
	private Date LrgsSince;

	/** The LRGS until time. */
	private Date LrgsUntil;

	/** Name of attached client. */
	private String clientName;

	/** The archive from which to serve data. */
	private MsgArchive msgArchive;

	/** the status structure */
	private AttachedProcess attachedProcess;

	/** The LRGS-timestamp of the last message retrieved by this user. */
	private int lastMsgDrotTime;

	/** Path name of file to save last time in. */
	private String lastPath;

	/** If true, then force the legacy slower ascending only retrieval. */
	private boolean _forceAscending = false;
	
	/** The DDS Version of the client on the other end. */
	private int ddsVersionNum = 5;
	private String ddsVersion = "" + ddsVersionNum;
	
	private boolean goodOnly = false;
	
	/**
	 * Constructor.
	 */
	public MessageArchiveRetriever(MsgArchive msgArchive, AttachedProcess ap)
	{
		super();
		searchHandle = null;
		LrgsSince = null;
		LrgsUntil = null;
		this.msgArchive = msgArchive;
		attachedProcess = ap;
		attachedProcess.lastSeqNum = 0;
		lastMsgDrotTime = 0;
		lastPath = null;
		_forceAscending = false;
	}
	
	/**
	 * call 'testCriteria' from the base class.
	 */
	public boolean passes( DcpMsgIndex mie )
	{
		// Our init search gets us to the correct minute. But we still
		// have to check the send if an LRGS Since time was specified.
		if (LrgsSince != null
		 && mie.getLocalRecvTime().compareTo(LrgsSince) < 0)
			return false;
		if (LrgsUntil != null
		 && mie.getLocalRecvTime().compareTo(LrgsUntil) > 0)
			return false;
		
		// We must not deliver Iridium messages to pre-version-9 clients!
		if (ddsVersionNum < 10 
		 && DcpMsgFlag.isIridium(mie.getFlagbits()))
			return false;
		
		// Added in OpenDCS 6.5
		if (goodOnly && DcpMsgFlag.isGOES(mie.getFlagbits()) && mie.getFailureCode() != 'G')
			return false;
//Logger.instance().info("passes: goodOnly=" + goodOnly + ", isGOES=" + DcpMsgFlag.isGOES(mie.getFlagbits()) 
//+ ", failCode=" + mie.getFailureCode());
		return testCriteria(mie);
	}
	
	/**
	 * If only DapsSince is specified use it, assume DapsTime <= LrgsTime.
	 * DapsSince is a Date attribute in the base class.
	 * @return since time for initializing the archive's retrieval.
	 */
	public Date getSinceTime( )
	{
		if (LrgsSince != null)
			return LrgsSince;
		return DapsSince;
	}
	
	/**
	 * If LrgsUntil is specified use it, else add a fudge factor to DapsUntil.
	 * Assumes LrgsTime is not too much later than DapsTime (e.g. 90 seconds).
	 * @return until time for terminating archive's retrieval.
	 */
	public Date getUntilTime( )
	{
		if (LrgsUntil != null)
			return LrgsUntil;
		else if (DapsUntil != null)
			return new Date(DapsUntil.getTime() + 90000L);
		return null;
	}

	/**
	 * The index should already contain the message, just return it.
	 */
	public DcpMsg readMsg( DcpMsgIndex idx )
	{
		lastMsgDrotTime = (int)(idx.getLocalRecvTime().getTime()/1000L);
		return idx.getDcpMsg();
	}
	
	/**
	 * Call super.init() to read netlists, addresses, & time ranges.
	 * Get searchHandle from Message Archive.
	 */
	public void init( )
		throws IOException, SearchSyntaxException, ArchiveUnavailableException
	{
		super.init();
		searchHandle = msgArchive.startSearch(this);
	}

	/**
	 * Template method to set explicit LRGS Until time.
	 * @param until the since time.
	 */
	protected void setLrgsUntilTime(Date until)
	{
		LrgsUntil = until;
	}


	/**
	  Retrieve the next index that passes the loaded criteria.
	  @param idx the DcpMsgIndex structure to populate
	  @param stopSearchMsec msec value at which to stop searching.
	  @return index number (i.e. the index of the index)

	  @throws ArchiveUnavailableException on internal archiving error
	  @throws UntilReachedException if specified until time was reached
	  @throws SearchTimeoutException if stopSearchMsec reached & no msg rcv'd
	   (this essentially means 'try again')
	  @throws EndOfArchivException if all indexes have been checked with no
	   match.

	 */
	public int getNextPassingIndex(DcpMsgIndex idx, long stopSearchMsec)
        throws ArchiveUnavailableException, UntilReachedException,
            SearchTimeoutException, EndOfArchiveException
	{
		// If there's a next index in searchHandle.idxBuf, return it.
		DcpMsgIndex ret = searchHandle.getNextIndex();
		if (ret != null)
		{
			idx.copyFrom(ret);
			attachedProcess.lastMsgTime = (int)(idx.getXmitTime().getTime()/1000L);
			attachedProcess.lastSeqNum++;
			return 1;
		}
		else if (System.currentTimeMillis() > stopSearchMsec)
			throw new SearchTimeoutException("Search Time Expired");

		Logger.instance().debug3("Starting search...");
		int result = msgArchive.search(searchHandle, stopSearchMsec);
		Logger.instance().debug3("Search Result=" + result);
		if (result == MsgArchive.SEARCH_RESULT_MORE
		 || result == MsgArchive.SEARCH_RESULT_DONE
		 || result == MsgArchive.SEARCH_RESULT_TIMELIMIT)
		{
			ret = searchHandle.getNextIndex();
			if (ret != null)
			{
				idx.copyFrom(ret);
				attachedProcess.lastMsgTime = (int)(idx.getXmitTime().getTime()/1000L);
				attachedProcess.lastSeqNum++;
				return 1;
			}
			else if (result == MsgArchive.SEARCH_RESULT_DONE)
				throw new UntilReachedException();
			else
				throw new SearchTimeoutException("Search Time Expired");
		}
		else if (result == MsgArchive.SEARCH_RESULT_PAUSE)
		{
			throw new EndOfArchiveException();
		}
		// Should never get here.
		throw new ArchiveUnavailableException(
			"Bad return from msgArchive.search: " + result,
			LrgsErrorCode.DDDSINTERNAL);
	}
	

	public DcpAddress[] getDcpAddresses()
	{
		return aggregateList;
	}

	/**
	* From DcpMsgSource interface, does nothing.
	*/
	public void attachSource()
	{
	}

	/**
	* From DcpMsgSource interface, does nothing.
	*/
	public void detachSource()
	{
		if (lastMsgDrotTime != 0 && lastPath != null)
		{
			File lastFile = new File(lastPath);
			try
			{
				FileWriter fw = new FileWriter(lastFile);
				fw.write(IDateFormat.time_t2string(lastMsgDrotTime) + "\n");
				fw.close();
			}
			catch(IOException ex)
			{
				Logger.instance().warning("Cannot save last-msg-time in '"
					+ lastPath + "': " + ex);
			}
			lastMsgDrotTime = 0;
		}
		attachedProcess.setName("");
		attachedProcess.pid = -1;
	}

	/**
	* Sets the client name for this connection. This name is used in
	* subsequent log messages, status displays, etc.
	* @param name the name
	*/
	public void setClientName(String name)
	{
		this.clientName = name;
		attachedProcess.setName(name);
	}
	
	public String getClientName() { return clientName; }
                                                                                
	/**
	* From DcpMsgSource interface, does nothing.
	* @param proctype process type
	* @param user user name
	*/
	public void setProcInfo(String proctype, String user)
	{
		attachedProcess.type = proctype;
		attachedProcess.user = user;
	}
                                                                                
	/**
	* From DcpMsgSource interface, does nothing.
	*/
	public int getNextIndex(DcpMsgIndex idx)
	{
		return -1;
	}
 
	/**
	* From DcpMsgSource interface, does nothing.
	*/
	public DcpMsg readMsgFromSource(DcpMsgIndex idx)
	{
		return null;
	}

	/**
	* Sets the since time for subsequent message retrievals.
	*/
	public boolean setSourceLrgsSinceTime(Date since)
	{
		LrgsSince = since;
		return true;
	}

	/**
	* Sets the until time for subsequent message retrievals.
	*/
	public void setSourceLrgsUntilTime(Date until)
	{
		setLrgsUntilTime(until);
	}

	/**
	* From DcpMsgSource interface.
	*/
	public boolean setSourceLrgsSinceLast() 
	{
		File lastFile = new File(lastPath);
		try
		{
			BufferedReader fr = new BufferedReader(new FileReader(lastFile));
			String lds = fr.readLine().trim();
			fr.close();
			LrgsSince = IDateFormat.parseJulianDate(lds);
		}
		catch(IOException ex)
		{
			Logger.instance().warning("Cannot read last-msg-time from '"
				+ lastPath + "': " + ex);
		}

		return true;
	}

	/**
	Set option for saving last index.
	The Java version always saves the file, but instead of containing the
	index in binary form, it just contains the ASCII date/time of the 
	LRGS time of the last message retrieved by this user. 
	The save is done when the user disconnects.
	@param path name of file to save last index in
	@param option must be either SaveLastNever or SaveLastOnGetIndex.
    */
    public void setSaveLast(String path, int option)
	{
		lastPath = path;
	}

	/**
	  Set this process's status.
	  @param stat the status string
	*/
	public void setStatus(String status)
	{
		attachedProcess.status = status;
	}
                                                                                

	/**
	 * This is part of the MsgFilter interface. It tells MsgArchive whether
	 * or not to force the legacy ascending-only (slower) retrieval method.
	 */
	public boolean forceAscending() 
	{
		return _forceAscending || crit.getAscendingTimeOnly();
	}

	/** Part of MsgFilter interface */
	public boolean realTimeSettlingDelay()
	{
		return crit.getRealtimeSettlingDelay();
	}

	/**
	 * Sets flag to force (or not force) the legacy ascending-only behavior.
	 */
	public void setForceAscending(boolean tf) { _forceAscending = tf; }
	
	public void setProtocolVersion(String version) 
	{
		int i=0;
		while(i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy