blob: f537a1b6f5c1a2d25a526871d0c928fccebc1e44 [file] [log] [blame]
/*
* Copyright (c) 2016, 2019 Eike Stepper (Loehne, 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.concurrent;
import org.eclipse.net4j.util.container.ContainerEventAdapter;
import org.eclipse.net4j.util.container.IContainer;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.container.IManagedContainerProvider;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.event.EventUtil;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.factory.ProductCreationException;
import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleException;
import org.eclipse.net4j.util.lifecycle.LifecycleState;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author Eike Stepper
* @since 3.6
*/
public class DelegableReentrantLock extends NonFairReentrantLock implements ILifecycle, IManagedContainerProvider
{
private static final long serialVersionUID = 1L;
private final IManagedContainer container;
private final IListener containerListener = new ContainerEventAdapter<Object>()
{
@Override
protected void onAdded(IContainer<Object> container, Object element)
{
addDelegateDetector(element);
}
@Override
protected void onRemoved(IContainer<Object> container, Object element)
{
removeDelegateDetector(element);
}
};
private final List<DelegateDetector> delegateDetectors = new CopyOnWriteArrayList<>();
private volatile boolean active;
public DelegableReentrantLock(IManagedContainer container)
{
this.container = container;
}
public DelegableReentrantLock()
{
this(IPluginContainer.INSTANCE);
}
@Override
public final IManagedContainer getContainer()
{
return container;
}
@Override
public final synchronized void activate() throws LifecycleException
{
if (!active)
{
active = true;
for (Object element : container.getElements(DelegateDetector.Factory.PRODUCT_GROUP))
{
addDelegateDetector(element);
}
container.addListener(containerListener);
}
}
@Override
public final synchronized Exception deactivate()
{
if (active)
{
try
{
container.removeListener(containerListener);
delegateDetectors.clear();
}
catch (Exception ex)
{
return ex;
}
finally
{
active = false;
}
}
return null;
}
@Override
public final LifecycleState getLifecycleState()
{
return active ? LifecycleState.ACTIVE : LifecycleState.INACTIVE;
}
@Override
public final boolean isActive()
{
return active;
}
@Override
public final void addListener(IListener listener)
{
// Do nothing
}
@Override
public final void removeListener(IListener listener)
{
// Do nothing
}
@Override
public final IListener[] getListeners()
{
return EventUtil.NO_LISTENERS;
}
@Override
public final boolean hasListeners()
{
return false;
}
@Override
protected boolean isOwner(Thread thread, Thread owner)
{
if (super.isOwner(thread, owner))
{
return true;
}
return isDelegate(thread, owner);
}
protected boolean isDelegate(Thread thread, Thread owner)
{
for (DelegateDetector delegateDetector : delegateDetectors)
{
if (delegateDetector.isDelegate(thread, owner))
{
return true;
}
}
return false;
}
private void addDelegateDetector(Object element)
{
if (element instanceof DelegateDetector)
{
DelegateDetector delegateDetector = (DelegateDetector)element;
delegateDetectors.add(delegateDetector);
}
}
private void removeDelegateDetector(Object element)
{
if (element instanceof DelegateDetector)
{
DelegateDetector delegateDetector = (DelegateDetector)element;
delegateDetectors.remove(delegateDetector);
}
}
/**
* @author Eike Stepper
*/
public interface DelegateDetector
{
public boolean isDelegate(Thread thread, Thread owner);
/**
* @author Eike Stepper
*/
public static abstract class Factory extends org.eclipse.net4j.util.factory.Factory
{
public static final String PRODUCT_GROUP = "org.eclipse.net4j.util.concurrent.delegateDetectors";
public Factory(String type)
{
super(PRODUCT_GROUP, type);
}
@Override
public abstract DelegateDetector create(String description) throws ProductCreationException;
}
}
}