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

com.aoindustries.aoserv.client.TableEventThread Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ platform.
 * Copyright (C) 2001-2012, 2016  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

/**
 * AOServTable events with a delay greater
 * than zero are processed in an asynchronous
 * TableEventThread.
 *
 * @see  AOServTable#addTableListener(TableListener)
 *
 * @author  AO Industries, Inc.
 */
public class TableEventThread extends Thread {

	private final AOServTable table;

	public TableEventThread(AOServTable table) {
		setName("TableEventThread #" + getId() + " ("+table.getTableID()+") - "+table.getClass().getName());
		this.table=table;
		setDaemon(true);
		start();
		// System.out.println("DEBUG: Started TableEventThread: "+getName());
	}

	@Override
	@SuppressWarnings("unchecked")
	public void run() {
		OUTER_LOOP :
		while(true) {
			try {
				synchronized(table.eventLock) {
					while(true) {
						if(table.thread!=this) break OUTER_LOOP;
						long time = System.currentTimeMillis();
						// Run anything that should be ran, calculating the minimum sleep time
						// for the next wait period.
						long minTime = Long.MAX_VALUE;
						// Get a copy to not hold lock too long
						List tableListenersSnapshot;
						synchronized(table.tableListenersLock) {
							tableListenersSnapshot = table.tableListeners==null ? null : new ArrayList<>(table.tableListeners);
						}
						if(tableListenersSnapshot!=null) {
							int size = tableListenersSnapshot.size();
							for (int c = 0; c < size; c++) {
								final TableListenerEntry entry = tableListenersSnapshot.get(c);
								// skip immediate listeners
								long delay = entry.delay;
								if(delay>0) {
									long delayStart = entry.delayStart;
									// Is the table idle?
									if (delayStart != -1) {
										// Has the system time been modified to an earlier time?
										if (delayStart > time) delayStart = entry.delayStart = time;
										long endTime = delayStart + delay;
										if (time >= endTime) {
											// Ready to run
											entry.delayStart = -1;
											// System.out.println("DEBUG: Started TableEventThread: run: "+getName()+" calling tableUpdated on "+entry.listener);
											// Run in a different thread to avoid deadlock and increase concurrency responding to table update events.
											AOServConnector.executorService.submit(
												new Runnable() {
													@Override
													public void run() {
														entry.listener.tableUpdated(table);
													}
												}
											);
										} else {
											// Remaining delay
											long remaining = endTime - time;
											if (remaining < minTime) minTime = remaining;
										}
									}
								}
							}
						}
						if(minTime==Long.MAX_VALUE) {
							// System.out.println("DEBUG: TableEventThread: run: "+getName()+" size="+size+", waiting indefinitely");
							table.eventLock.wait();
						} else {
							// System.out.println("DEBUG: TableEventThread: run: "+getName()+" size="+size+", waiting for "+minTime+" ms");
							table.eventLock.wait(minTime);
						}
					}
				}
			} catch (ThreadDeath TD) {
				throw TD;
			} catch (Throwable T) {
				table.connector.logger.log(Level.SEVERE, null, T);
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy