/* * Copyright (c) 2009-2013, 2015, 2016 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eike Stepper - initial API and implementation */ package org.eclipse.net4j.util.om.monitor; import org.eclipse.net4j.internal.util.bundle.OM; import org.eclipse.net4j.util.concurrent.TrackableTimerTask; import org.eclipse.net4j.util.om.OMPlatform; import java.util.Timer; import java.util.TimerTask; /** * @author Eike Stepper * @since 2.0 */ public abstract class AbstractMonitor implements OMMonitor { private static final boolean CHECK_BEGIN = OMPlatform.INSTANCE.isProperty("org.eclipse.net4j.util.om.monitor.CheckBegin"); private static final long NOT_BEGUN = -1; private double totalWork = NOT_BEGUN; private double work; public AbstractMonitor() { } public boolean hasBegun() throws MonitorCanceledException { checkCanceled(); return totalWork != NOT_BEGUN; } public OMMonitor begin(double totalWork) throws MonitorCanceledException { checkCanceled(); this.totalWork = totalWork; return this; } public OMMonitor begin() throws MonitorCanceledException { return begin(ONE); } public void worked(double work) throws MonitorCanceledException { checkBegun(); this.work += work; } public void worked() throws MonitorCanceledException { worked(ONE); } public OMMonitor fork(double work) { checkBegun(); return createNestedMonitor(work); } public OMMonitor fork() { return fork(ONE); } public Async forkAsync(double work) { checkBegun(); AsyncTimerTask asyncTimerTask = createAsyncTimerTask(work); if (asyncTimerTask == null) { throw new NullPointerException("No async timer task has been created"); } long period = getAsyncSchedulePeriod(); scheduleAtFixedRate(asyncTimerTask, period, period); return asyncTimerTask; } public Async forkAsync() { return forkAsync(ONE); } public void done() { if (!isCanceled()) { double rest = totalWork - work; if (rest > 0) { worked(rest); } } } public double getTotalWork() { return totalWork; } public double getWork() { return work; } public double getWorkPercent() { return percent(work, totalWork); } protected OMMonitor createNestedMonitor(double work) { return new NestedMonitor(this, work); } protected AsyncTimerTask createAsyncTimerTask(double work) { return new AsyncTimerTask(this, work, DEFAULT_TIME_FACTOR); } protected abstract long getAsyncSchedulePeriod(); protected abstract Timer getTimer(); /** * @since 3.0 */ protected abstract void scheduleAtFixedRate(TimerTask task, long delay, long period); private void checkBegun() throws MonitorCanceledException { if (CHECK_BEGIN && !hasBegun()) { throw new IllegalStateException("begin() has not been called"); //$NON-NLS-1$ } } /** * @since 3.1 */ protected static double percent(double part, double whole) { return Math.min(part * HUNDRED / whole, HUNDRED); } /** * @author Eike Stepper */ public static class AsyncTimerTask extends TrackableTimerTask implements Async { private OMMonitor monitor; private boolean canceled; public AsyncTimerTask(AbstractMonitor parent, double parentWork, double timeFactor) { monitor = parent.fork(parentWork); monitor.begin(); } @Override public void run() { try { if (!canceled && monitor != null) { double work = 1 - monitor.getWork(); monitor.worked(work / TEN); } } catch (Exception ex) { OM.LOG.error("AsyncTimerTask failed", ex); } } public void stop() { try { if (monitor != null) { monitor.done(); } cancel(); } catch (Exception ex) { OM.LOG.error(ex); } } @Override public boolean cancel() { canceled = true; monitor = null; return super.cancel(); } } }