blob: 3e5781cee7166369c4c405c267ff4e658a27346c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* SAP AG - initial API and implementation
******************************************************************************/
package org.eclipse.ocl.examples.eventmanager.framework;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.logging.Logger;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
/**
* Observes a {@link ReferenceQueue reference queue} and removes {@link Adapter}s
* from it. It weakly references an {@link EventManagerTableBased}. When a
* reference to an adapter was added to the queue and henceforth removed by this
* thread, this means that the adapter is no longer strongly referenced. A
* {@link EventManagerTableBased#deregister(Reference)} is issued to clean up
* after the adapter.
* <p>
*
* When the {@link EventManagerTableBased event manager} becomes eligible for
* garbage collection, its {@link EventManagerTableBased#finalize()} method
* stops this thread by calling {@link #stopCleaner()}.
*
* @author Axel Uhl (d043530)
*
*/
public class CleanupThread extends Thread {
private Logger logger = Logger.getLogger(CleanupThread.class.getName());
private final ReferenceQueue<Adapter> adaptersNoLongerStronglyReferenced;
private final WeakReference<EventManagerTableBased> eventManagerRef;
/**
* A dummy adapter used by {@link #stopThreadMarker}. In order to stop the
* {@link #adapterCleanupThread}, this field must be set to
* <code>null</code>, causing the adapter to be no longer stongly
* referenced. This, in turn, will cause the {@link #stopThreadAdapter}
* reference to be enqueued in {@link #adaptersNoLongerStronglyReferenced}
* from where it is removed by {@link #adapterCleanupThread}. Successful
* comparison to {@link #stopThreadMarker} causes the thread to terminate.
*/
private Adapter stopThreadAdapter;
/**
* Used to signal the {@link #adapterCleanupThread} to stop the thread.
*/
private final WeakReference<Adapter> stopThreadMarker;
public CleanupThread(
ReferenceQueue<Adapter> adaptersNoLongerStronglyReferenced,
EventManagerTableBased eventManager) {
super("CleanupThread for event manager "+eventManager);
this.adaptersNoLongerStronglyReferenced = adaptersNoLongerStronglyReferenced;
this.stopThreadAdapter = new AdapterImpl();
this.stopThreadMarker = new WeakReference<Adapter>(stopThreadAdapter,
adaptersNoLongerStronglyReferenced);
this.eventManagerRef = new WeakReference<EventManagerTableBased>(
eventManager);
}
/**
* Indirectly but cleanly stops this thread. This happens by nulling the
* {@link #stopThreadAdapter} field which was the only strong reference to
* the adapter held by it. The weak reference in {@link #stopThreadMarker}
* will therefore be enqueued which serves as the stop marker, causing the
* {@link #run} loop to terminate.
*/
public void stopCleaner() {
stopThreadAdapter = null; // causes stopThreadMarker to get enqueued
// which stops adapterCleanupThread
}
public void run() {
try {
Reference<? extends Adapter> adapterRef = adaptersNoLongerStronglyReferenced
.remove();
while (adapterRef != stopThreadMarker) {
EventManagerTableBased eventManager = eventManagerRef.get();
if (eventManager != null) {
eventManager.deregister(adapterRef);
}
adapterRef = adaptersNoLongerStronglyReferenced.remove();
}
} catch (InterruptedException e) {
// Why are we being interrupted? log incident and terminate thread.
logger.throwing(this.getClass().getName(), "run", e);
}
}
}