001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2017-2026 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
013 * License for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.core.internal;
020
021import java.time.Instant;
022import org.jgrapes.core.Components;
023
024/**
025 * The base class for completeion locks.
026 */
027@SuppressWarnings({ "PMD.AbstractClassWithoutAbstractMethod",
028    "PMD.AvoidSynchronizedStatement" })
029public abstract class CompletionLockBase {
030
031    private final EventBase<?> event;
032    private final long timeout;
033    private Components.Timer timer;
034
035    /**
036     * @param event the event to be locked
037     * @param timeout
038     */
039    protected CompletionLockBase(EventBase<?> event, long timeout) {
040        this.event = event;
041        this.timeout = timeout;
042        event.addCompletionLock(this);
043    }
044
045    /* default */ long getTimeout() {
046        return timeout;
047    }
048
049    /**
050     * Removes this completion lock from the event that it was created for.
051     * 
052     * This method may be invoked even if the completion lock has already
053     * been removed. This allows locks to be used for disjunctive wait.
054     */
055    public void remove() {
056        event.removeCompletionLock(this);
057    }
058
059    /* default */ CompletionLockBase startTimer() {
060        if (timeout == 0) {
061            return this;
062        }
063        timer = Components.schedule(scheduledFor -> {
064            event.removeCompletionLock(this);
065        }, Instant.now().plusMillis(timeout));
066        return this;
067    }
068
069    /* default */ void cancelTimer() {
070        synchronized (this) {
071            if (timer != null) {
072                timer.cancel();
073                timer = null;
074            }
075        }
076    }
077}