package au.gov.ga.earthsci.model.render;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.inject.Inject;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import au.gov.ga.earthsci.common.util.ExtensionRegistryUtil;
import au.gov.ga.earthsci.common.util.ExtensionRegistryUtil.Callback;
import au.gov.ga.earthsci.model.geometry.IModelGeometry;
/**
* A registry used to retrieve {@link IModelGeometryRendererCreator} instances
* for a given {@link IModelGeometry} instance.
* <p/>
* Creators can be registered with the registry programmatically using
* {@link #registerCreator(IModelGeometryRendererCreator) registerCreator}, or
* via the {@value #EXTENSION_POINT_ID} extension point.
*
* @author James Navin (james.navin@ga.gov.au)
*/
public class RendererCreatorRegistry
{
private static final Logger logger = LoggerFactory.getLogger(RendererCreatorRegistry.class);
public static final String EXTENSION_POINT_ID = "au.gov.ga.earthsci.model.render.geometryRendererCreators"; //$NON-NLS-1$
public static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
private static final List<IModelGeometryRendererCreator> creators = new ArrayList<IModelGeometryRendererCreator>();
private static final ReadWriteLock creatorsLock = new ReentrantReadWriteLock();
/** A default catch-all creator. Can be overridden by injection */
private static IModelGeometryRendererCreator globalCreator = new LoggingGeometryRendererCreator();
/**
* Load {@link IModelGeometryRendererCreator}s registered against the
* {@value #EXTENSION_POINT_ID} extension point.
*/
@Inject
public static void loadFromExtensions(IEclipseContext context)
{
logger.debug("Registering model geometry renderer creators"); //$NON-NLS-1$
try
{
ExtensionRegistryUtil.createFromExtension(EXTENSION_POINT_ID, CLASS_ATTRIBUTE,
IModelGeometryRendererCreator.class, context, new Callback<IModelGeometryRendererCreator>()
{
@Override
public void run(IModelGeometryRendererCreator creator, IConfigurationElement element,
IEclipseContext context)
{
registerCreator(creator);
}
});
}
catch (Exception e)
{
logger.error("Exception occurred while registering model geometry renderer creators", e); //$NON-NLS-1$
}
}
/**
* Register the given creator with the registry.
*
* @param creator
* The creator to register
*/
public static void registerCreator(IModelGeometryRendererCreator creator)
{
if (creator == null)
{
return;
}
logger.debug("Registering model geometry renderer creator: {} ({})", creator.getName(), //$NON-NLS-1$
creator.getClass().getSimpleName());
try
{
creatorsLock.writeLock().lock();
creators.add(creator);
}
finally
{
creatorsLock.writeLock().unlock();
}
}
/**
* Retrieve the list of registered {@link IModelGeometryRendererCreator}s
* that support the given {@link IModelGeometry} instance, if any.
* <p/>
* If no creators are found that support the given geometry, will return the
* empty list.
*
* @param geometry
* The geometry for which a creator is required
*
* @return The list of registered {@link IModelGeometryRendererCreator}s
* that support the given geometry instance, or the empty list if
* none are found.
*/
public static List<IModelGeometryRendererCreator> getCreators(IModelGeometry geometry)
{
try
{
creatorsLock.readLock().lock();
List<IModelGeometryRendererCreator> result = new ArrayList<IModelGeometryRendererCreator>();
for (IModelGeometryRendererCreator creator : creators)
{
if (creator.supports(geometry))
{
result.add(creator);
}
}
return result;
}
finally
{
creatorsLock.readLock().unlock();
}
}
/**
* Return the default {@link IModelGeometryRendererCreator} for the given
* geometry instance. If no default has been set, the first creator found
* that supports the geometry will be used. If no creators are found that
* support the geometry, will return <code>null</code>.
*
* @param geometry
* The geometry a creator is required for
*
* @return A creator to use for the given geometry, or <code>null</code> if
* none are found.
*/
public static IModelGeometryRendererCreator getDefaultCreator(IModelGeometry geometry)
{
// TODO Add support for a 'default' creator for the geometry type
List<IModelGeometryRendererCreator> creators = getCreators(geometry);
if (creators == null || creators.isEmpty())
{
return globalCreator;
}
return creators.get(0);
}
/**
* Override the default global renderer creator.
*/
public static void setDefaultGlobalCreator(IModelGeometryRendererCreator defaultCreator)
{
RendererCreatorRegistry.globalCreator = defaultCreator;
}
}